basic/자료구조 & 알고리즘

[알고리즘/자료구조] 링크드 리스트(linked list)

NoelBird 2019. 7. 31. 00:22

링크드 리스트는 '노드를 연결해서 만드는 리스트'를 의미하고, 노드는 데이터와 다른 노드를 가리키는 포인터로 이루어져 있습니다.

 

C언어에서 링크드 리스트를 표현하면 다음과 같이 표현할 수 있습니다.

#include<stdio.h>

struct Node {
	int data;
	struct Node* nextNode;
};

int main() {
	struct Node MyNode;
	return 0;
}

 

typedef로 짧은 이름을 부여할 수도 있습니다.

#include<stdio.h>

typedef struct tagNode{
	int data;
	struct Node* nextNode;
} Node;

int main() {
	Node MyNode;
	return 0;
}

 

링크드 리스트의 주요 연산은 다음과 같습니다.

- 노드 생성/소멸(create/destroy)

Node* createNode(int newData) {
	Node* newNode = (Node*)malloc(sizeof(Node));
	newNode->data = newData;
	newNode->nextNode = NULL;

	return newNode;
}

void destroyNode(Node* Node) {
	free(Node);
}

 

- 노드 추가(append): 링크드리스트의 꼬리 노드 뒤에 새로운 노드를 생성 후 연결하는 것을 의미합니다.

void appendNode(Node** Head, Node* NewNode) {
	if ((*Head) == NULL) {
		*Head = NewNode;
	}
	else {
		Node* Tail = (*Head);
		while (Tail->nextNode != NULL) {
			Tail = Tail->nextNode;
		}

		Tail->nextNode = NewNode;
	}
}

int main() {
	Node* List = NULL;
	Node* NewNode = NULL;

	NewNode = createNode(117);
	appendNode(&List, NewNode);

	NewNode = createNode(119);
	appendNode(&List, NewNode);
	return 0;
}

 

- 노드 탐색: 탐색 연산은 인덱스를 이용해 접근할 수 없고, 차근차근 노드의 수를 세어가야합니다. (링크드 리스트의 엄청난 단점입니다. 아이템에 인덱스를 이용해 바로 접근할 수 없다니...!!)

Node* getNodeAt(Node* Head, int location) {
	Node* Current = Head;
	while (Current != NULL && (--location) >= 0) {
		Current = Current->nextNode;
	}
	return Current;
}

int main() {
	Node* List = NULL;
	Node* MyNode = NULL;

	appendNode(&List, createNode(117));
	appendNode(&List, createNode(119));

	MyNode = getNodeAt(List, 1);
	printf("%d\n", MyNode->data);
	return 0;
}

 

- 노드 삭제: 노드 삭제 연산은 링크드 리스트 내에 있는 임의의 노드를 제거하는 연산입니다. 삭제하고자 하는 노드를 찾은 후, 해당 노드의 다음 노드를 이전 노드의 NextNode 포인터에서 제거하면 됩니다.

void removeNode(Node** Head, Node* Remove) {
	if (*Head == Remove) {
		*Head = Remove->nextNode;
	}
	else {
		Node* Current = *Head;
		while (Current != NULL && Current->nextNode != Remove) {
			Current = Current->nextNode;
		}
		if (Current != NULL) {
			Current->nextNode = Remove->nextNode;
		}
	}
}

int main() {
	Node* List = NULL;
	Node* MyNode = NULL;

	appendNode(&List, createNode(117));
	appendNode(&List, createNode(119));
	appendNode(&List, createNode(212));

	MyNode = getNodeAt(List, 1);
	printf("%d\n", MyNode->data);

	removeNode(&List, MyNode); // 두 번째 노드 제거

	destroyNode(MyNode); // 링크드 리스트에서 제거한 노드를 메모리에서 완전히 소멸시킴;
	return 0;
}

 

- 노드 삽입

void insertAfter(Node* Current, Node* NewNode) {
	NewNode->nextNode = Current->nextNode;
	Current->nextNode = NewNode;
}

 

- 노드 개수 세기: 링크드 리스트 내에 존재하는 노드의 수를 세어 반환함.

int getNodeCount(Node* Head) {
	int Count = 0;
	Node* Current = Head;

	while (Current != NULL) {
		Current = Current->nextNode;
		Count++;
	}

	return Count;
}