List
LIST
List란? (pointer를 기반)
- ‘일정한 순서’의 나열
- 어떤 정의에 의해서 결정된 ‘논리적인 순서’의 나열
논리적 순서와 물리적 순서
- 리스트의 ‘순서’는 데이터가 저장되는 물리적인 위치와 상관없이 사람들의 머리속에 인식되는 ‘논리적인 순서’, 혹은 리스트에 나타나는 원소들간의 ‘의미적인 순서’를 의미
- pointer를 따라가면 순서대로 접근이 가능하다.
- 배열은 인덱스로 표현되는 ‘순서’가 배열 원소의 메모리공간(DDR)에서의 물리적인 위치를 의미
- 리스트의 ‘순서’개념은 어떤 정의에 의해 결정된 '논리적인 순서'
- 원소들의 물리적인 저장 순서나 위치와는 무관하게 원소들간의 논리적인 순서만 유지
리스트의 구현 방법
-
포인터를 이용한 리스트 구현 방법: 원소값을 저장하는 공간과 다음 원소를 가리키는 위치 정보를 저장하는 공간을 함께 구현하는 방법(연결 리스트)
-
배열을 이용한 리스트의 구현 방법
배열을 이용한 리스트 구현
리스트를 배열로 구현하고 난 뒤에 중간에 다른 데이터를 삽입해야 한다면?
-
배열의 확장: 초기 배열 선언에서 충분히 크게 하면 어느 정도는 배열의 추가 확장을 피할 수 있다. 그러나 원소를 리스트의 중간에 삽입하기 위해서는 리스트의 원소 값을 하나씩 뒤로 밀어야 한다.
- 배열이라는 자료구조는 직관적이지만, 고정적. 변동에 있어서 취약
- 배열은 중간에 ‘빈 값’이 허용되지 않음
-
‘배열로 구현된 리스트’는 원소의 순서가 연속적인 물리적 주소에 저장
- 원소를 삽입하거나 삭제하기 위해서는 해당 원소의 위치 뒤에 있는 모든 원소를 뒤로 물리거나 앞으로 당겨야 한다.
- 리스트 원소 값의 이동은 원소수가 많을수록 프로그램의 수행시간을 증가시킨다.
포인터를 이용한 리스트의 구현
-
노드(node): 리스트위 원소(값) + 다음 원소를 가리키는 정보(메모리 주소값)
노드는 데이터 요소(원소, 값)와 리스트의 다음 원소를 지시하는 포인터(주소, 링크(link))로 구성됨
-
링크, 일종의 주소값
-
포인터 변수 및 리스트의 삭제/삽입
-
리스트의 생성
정수값 data와 링크로 구성된 노드의 생성
struct linked_list_node { int data; struct linked_list_node*link; }
-
포인터의 구현
- 포인터의 할당과 반환 예
int a, *p_a; float b, *p_b; p_a = (int*)malloc(sizeof(int)); p_b = (float*)malloc(sizeof(float)); *p_a = 10; *p_b = 3.14; printf("a is %d, b is %f\n", *p_a, *p_b); free(p_a); free(p_b);
-
malloc(memory allocation, 메모리 할당): 실행 중에 필요한 메모리를 할당받는 것
-
*은 포인터
*p_a = 10
은 포인터 자체의 값에 10이 저장되는 것이 아닌, p_a가 가르키는 (새롭게 메모리를 할당받은)주소값 공간. pointer가 선언되면 pointer의 주소값이 저장될 메모리와, 주소값이 가르킬 공간이 생성된다.
연결 리스트에서 노드의 삽입과 삭제
-
연결 리스트의 초기 모습
-
리스트의 원소 삭제 연산 단계
- 삭제할 노드의 선행 노드의 링크 필드를 삭제할 노드의 후행 노드를 가르키게 한다.
- 삭제할 노드를 메모리에 반환한다.
- 단계(순서)
- 메모리 공간을 할당받고 삽입할 내용을 저장하여 삽입할 x노드를 생성
- x노드의 링크부분이 후행 노드가 될 j노드를 가르키게 지시
- 삽입될 x노드의 선행 노드가 될 i 노드의 링크 필드가 x노드를 가르키게 함
-
예시) 연결 리스트의 마지막에 삽입 연산
void addNode(linkedList_h* H, int x){ //리스트 마지막 노드에 삽입 연산, x값은 100이라고 가정 listNode*NewNode; listNode*LastNode; NewNode = (listNode*)malloc(sizeof(listNode)); NewNode -> data = x; NewNode -> link = NULL; }
void addNode(linkedList_h* H, int x){ if(H -> head == NULL) { //현재 리스트가 공백인 경우 H -> head = NewNode; return; } LastNode = H -> head; while(LastNode -> link != NULL) LastNode = LastNode -> link; LastNode -> link = NewNode; }