프로그래머가 작성한 소스 파일로 부터 프로그램이 시작하며, hello.c라는 텍스트 파일로 저장된다.
소스 프로그램은 비트들의 연속이며, 8바이트 단위로 구성된다.
컴퓨터 시스템은 텍스트 문자를 아스키(ASCII) 표준을 통해 표현한다. 프로그램은 연속된 바이트들로 파일에 저장되고 각 바이트는 특정 문자에 대응하는 정수값을 갖는다.
hello.c처럼 아스키 문자로만 이루어진 파일을 텍스트 파일
이라고 하며, 나머지 다른 파일들을 바이너리 파일
이라고 한다.
프로그램을 통해 우리에게 전달될 때 시스템 내부의 정보 / 디스크 파일 / 메모리상 프로그램 / 데이터 네트워크를 통해 전달되는 데이터들은 모두 비트로 표현된다.
서로다른 객체를 구분하는 유일한 방식은 컨텍스트다. 다른 컨텍스트에 존재하는 바이트에 명령을 할 수 없다.
텍스트 파일을 시스템에서 실행시키기 위해서는 다른 언어, 기계가 이해할 수 있는 언어로 번역이 필요하다.
C 소스코드의 경우 각 문장들이 다른 프로그램에 의해 저급 기계어 인스트럭션으로 번역되고, 이 인스트럭션들ㅇ이 합쳐져 실행가능 목적 프로그램( a.k.a 실행가능 목적 파일 )의 형태로 바이너리 디스크에 저장된다.
소스 코드를 실행하기 위해 4가지 단계( 전처리기, 컴파일러, 어셈블러, 링커 )를 거치는데 이를 모두 합쳐 컴파일
시스템이라고 부른다.
# include<stdio.h>
에 대해서 직접 해당 프로그램 문장을 삽입한다. 전처리 단계가 끝난 후 .i
확장자의 새로운 프로그램이 생성된다..i
파일을 .s
로 번역하며, 이 때 파일 내에는 어셈블리어 프로그램
이 저장된다. 어셈블리어는 상위수준 언어의 컴파일러를 위한 공통의 출력 언어를 제공하기 때문에 유용하다.1.4.1 시스템의 하드웨어 조직
1.4.2 프로그램의 실행
자료구조 알고리즘에 따라 3가지 검색 방식이 존재한다.
반복문을 통해서 정렬되지 않은 배열을 검색하는 유일한 방법
검색이 끝나는 조건
보초법
검색 대상을 찾지 못한 경우 검색을 종료하는 조건에 대해서 비용을 절약할 수 있는 방법.
임의로 검색하는 값을 검색 대상 배열의 맨 마지막에 삽입해서 어떠한 경우에서도 검색이 되도록 해서 종료조건을 하나로 만들 수 있다.
import copy
def seq_search(seq: Sequence, key: Any) -> int:
a = copy.deepcopy(seq)
a.append(key)
i = 0
while True:
if a[i] == key:
break
i += 1
return -1 if i == len(a) else i
오름차순, 내림차순에 정렬된 배열에서 효율적인 검색을 수행할 수 있는 방법
검색이 끝나는 조건
def bin_search(a: Sequence, key: Any) -> int:
pl = 0
pr = len(a) - 1
while True
pc= (pl + pr) // 2
if a[pc] == key:
return pc
elif a[pc] < key:
pl = pc - 1
else:
pr = pc - 1
if pl > pr:
break
return -1
검색, 데이터 추가, 삭제를 효율적으로 할 수 있다.
해시법은 ‘데이터를 저장할 위치 = 인덱스’를 간단한 연산으로 구하는 것을 말한다. 이 때 이 값을 해시 값이라고 하며 데이터 접근의 기준이 된다. 그리고 해시 값을 인덱스로 하여 원소를 새롭게 저장한 배열이 해시 테이블(Hash Table)이라고 하며, 키를 해시값으로 변환하는 과정을 해시 함수(Hash Function)이라고 한다. 해시테이블에서 마들어진 원소를 버킷이라고 한다.
해시 충돌
버킷이 중복되는 현상을 해시 충돌이라고 한다. 키와 해시 값은 n:1을 가져 잘못된 방식은 아니지만 최대한 고르게 값이 분포될 수 있도록 하는 것이 중요하다.
해시 충돌을 해결할 수 있는 방법은 ‘체인법’과 ‘오픈 주소법’이 있다.
체인법
해시값이 같은 데이터를 링크드리트로 연결하는 방법이다. 이때 버킷에 저장되는 값은 각 링크드 리스트의 맨 앞쪽 노드의 참조값을 가지게 된다.
class ChainedHash:
def __init__ (self, capacity: int) -> None:
self.capacity = capacity
self.table = [None] * self.capacity
def hash_value(self, key: Any) -> int:
if isinstance(key, int):
return key % self.capacity
return(int(hashlib.sha256(str(key).encode()).hexdigit(), 16) % self.capacity)
def search(self, key: Any) -> Any:
hash = self.hash_value(key)
p = self.table[hash]
while p is not None:
if p.key == key:
return p.value
p = p.next
return None
def add(self, key: Any, value: Any) -> Any:
hash = self.hase_value(key)
p = self.table[hash]
while p is not None:
if p.key == key:
return False
p = p.next
temp = Node(key, value, self.table[hash])
self.table[hash] = temp
return True
def remove(self, key: Any) -> bool:
hash = self.hash_value(key)
p = self.table[hash]
pp = None
while p is not None:
if p.key == key:
if pp is not None:
self.table[hash] = p.next
else:
pp.next = p.next
return True
pp = p
p = p.next
return False
오픈 주소법
충돌이 발생했을 때 재해시를 수행해서 빈 버킷을 찾는 방법을 말하며, 닫힌 해시법이라고도 한다.
sorted()는 배열을 인자로 받아 정렬한 후 새로운 배열을 return해준다.
.sort()의 경우 list 타입의 내장 함수로 기존 리스트를 정렬하여 사용한다.
이진 탐색(Binary Search)와 유사한 알고리즘 : 시간 복잡도 ( O(logN)
매개변수 param과 결정함수 fn(param)
이진 탐색(Binary Search)와의 차이점