장점
메모리의 형태가 덩어리 형태로 연속적으로 할당되어, 특정 원소에 접근을 할 때 인덱스를 통해 굉장히 빠르게 접근할 수 있다.
배열의 크기가 커도 접근 속도는 항상 일정하다.
단점
원소를 추가하거나 삭제하려고 할 때 데이터의 이동하는 횟수가 너무 많아질 수 있다.
데이터가 정렬된 상태를 유지해야 할 경우에 단순히 맨 뒤에다가 원소를 추가하는 방법은 사용할 수가 없다.
장점
메모리의 형태가 노드 형태로 비연속적으로 할당되어, 원소를 추가하거나 삭제하려고 할 때 데이터의 이동이 필요하지 않고 연결 구조만 바꿔주면 된다.
단점
원소에 접근하려면 헤드(head)부터 차례대로 접근하는 수 밖에 없어서 접근 속도가 느리다.
데이터의 추가와 삭제가 빈번한 프로그램이라면 연결 리스트를 사용하는게 좋고,
삽입과 추가는 없고 접근만 하는 프로그램이라면 배열을 사용하는게 좋다.
값을 저장할 value와 다음 노드의 주소를 저장할 next를 선언해준다.
typedef struct node
{
int value; // 값 저장
struct node* next; // 다음 노드의 주소를 저장
}node;
node* head = NULL; // 시작노드의 주소를 저장할 head 포인터 지정
설명
맨 앞 노드는 항상 head 가 가리키고 있기 때문에 head 다음 노드를 새로운 노드가 가리키게 하고 head 가 새로운 노드를 가리키게 하면 된다.
순서
#include <stdio.h>
#include <stdlib.h>
// 구조체 생략
node* head = NULL;
void insert_node_front()
{
node* newNode = (node*)malloc(sizeof(node));
scanf("%d", &newNode->value);
newNode->next = NULL;
if (head == NULL)
{
head = newNode;
return;
}
newNode->next = head;
head = newNode;
}
설명
head 부터 차례대로 값을 저장할 변수를 만들고 그 변수의 값을 출력한다.
순서
#include <stdio.h>
#include <stdlib.h>
// 구조체 생략
node* head = NULL;
void displayNode()
{
if (head == NULL)
{
printf("연결 리스트가 구성되지 않아 출력할 값이 없습니다.\n");
return;
}
node* curNode = head; // 방문할 노드의 주소를 저장할 변수 생성, 시작은 head부터.
while (curNode->next != NULL)
{
printf("%d ", curNode->value);
curNode = curNode->next; // 다음 노드를 방문한다.
}
printf("%d\n", curNode->value); // 마지막 노드가 출력되게 끔
}
설명
연결 리스트를 마지막 노드까지 순회하고 새로운 값을 마지막 노드가 가리키게 한다.
순서
// 헤더 생략
// 구조체 생략
node* head = NULL;
void insert_node_rear()
{
node* newNode = (node*)malloc(sizeof(node));
scanf("%d", &newNode->value);
newNode->next = NULL;
if (head == NULL)
{
head = newNode;
return;
}
node* curNode = head;
while (curNode->next != NULL)
{
curNode = curNode->next; // 다음 노드를 방문한다.
}
curNode->next = newNode; // 마지막 노드에 새 노드를 삽입한다.
}
설명
연결 리스트 구조를 유지하기위해 head 의 다음 노드를 계속 head로 저장해 가면서 차례대로 삭제해 나간다.
순서
// 헤더 생략
// 구조체 생략
node* head = NULL;
void removeAllNode()
{
if (head == NULL)
{
printf("삭제할 데이터가 없습니다.\n");
return;
}
node* delNode = head;
while (head != NULL)
{
head = head->next;
free(delNode);
delNode = head;
}
}
설명
4가지 경우를 생각할 수 있다.
첫번째, head 가 NULL 일 때
두번째, 가장 작은 수를 삽입할 때 (head 의 값이 새로운 노드보다 클 때)
세번째, 중간에 삽입할 때 (새로운 값이 순회하는 노드의 값보다 작을 때)
네번째, 가장 큰 수를 삽입할 때 (마지막까지 노드가 순회해도 새로운 노드의 값보다 작을 때)
순서
// 헤더 생략
// 구조체 생략
node* head = NULL;
void insert_node_sort()
{
node* newNode = (node*)malloc(sizeof(node));
scanf("%d", &newNode->value);
newNode->next = NULL;
// case 1. head 가 null일 때
if (head == NULL)
{
head = newNode;
return;
}
// case 2. 가장 작은 값을 삽입
if (head->value > newNode->value)
{
newNode->next = head->next;
head = newNode;
return;
}
// case 3. 중간에 삽입
node* curNode, * prevNode; // 이전 노드 저장할 prevNode 도 선언
curNode = prevNode = head;
while (curNode->next != NULL)
{
curNode = curNode->next; // 값이 가장 작을 때는 위에서 이미 걸러 냈기 때문
if (curNode->value > newNode->value)
{
newNode->next = curNode;
prevNode->next = newNode;
return;
}
prevNode = prevNode->next;
}
// case 4. 가장 큰 값을 삽입
curNode->next = newNode;
}
값을 저장할 value와 다음 노드를 저장할 next, 이전 노드를 저장할 prev 변수를 선언해준다.
typedef struct dNode
{
int value;
struct dNode* next;
struct dNode* prev;
}dNode;
dNode* dHead = NULL;
설명
head 부터 순회해 가면서 prev 와 next 를 swap 해주면 역순으로 연결된다.
순서
// 헤더 생략
// 구조체 생략
dNode* head = NULL;
void reverse_dNode()
{
dNode* curNode = head;
dNode* temp;
// 노드가 없거나, 하나인 경우 예외 처리
if (head == NULL || head->next == NULL)
return;
while (curNode != NULL)
{
// swap
temp = curNode->next;
curNode->next = curNode->prev;
curNode->prev = temp;
if (curNode->prev == NULL) // 마지막 노드 일 때 head 가 가리키게 해준다.
{
head = curNode;
return;
}
curNode = curNode->prev; // swap 한 이후라 prev 로 다음 노드로 이동
}
}
유익한 글이었습니다.