본문 바로가기
코스웨어/16년 스마트컨트롤러

2016-09-07_조재찬_스터디일지_C언어-Linked List

by 알 수 없는 사용자 2016. 9. 8.
728x90
반응형

연결리스트 (Linked List)


연결리스트의 구현을 이해하기 위해서는,

malloc 함수와 free함수 기반의 메모리 동적할당에 대한 완전한 이해가 필요



배열은 index를 이용해 순차 접근이 가능한 자료구조

배열은 기본적으로 정적이다. (길이의 변경 불가능)


#include <stdio.h>

int main(void)
{
	int arr[10];
	int readCount = 0;
	int readData;
	int i;

	while (1)
	{
		printf("자연수 입력 (0이하 값 입력시 종료): ");
		scanf("%d", &readData);
		if (readData < 1)
			break;

		arr[readCount++] = readData;
	}

	for (i = 0; i<readCount; i++)
		printf("%d  ", arr[i]);

	return 0;
}



위의 예제에서 0 이하의 값을 입력하지 않고, 

계속해서 할당된 배열의 길이를 넘어서는 입력을 할 시 디버그 에러가 나게 된다.


이를 해결하기 위해선 메모리의 동적할당을 이용해야 한다.



* head : 첫번째 node를 가리키기 위함

* tail : head와 달리 필요없을 수도 있음


* cur : (current) 순차접근을 위한 것



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//노드의 머리에 추가하는 연결리스트
 
/* 노드 추가 과정 (동적 할당) */
    Node * newNode = NULL;
    newNode = (Node *)malloc(sizeof(Node));
    newNode->data = readData;
    newNode->next = NULL;
 
    if (head == NULL)
    {
      head = newNode;
      //tail = newNode;
    }
    else
    {
      newNode->next = head;
      head = newNode;
    }
  }
cs



새 노드를 연결리스트 머리에 추가하는 경우는, * tail이 불필요하지만 저장된 순서가 역순이 된다.


꼬리에 추가하는 경우는 저장된 순서가 유지되지만 * tail이 필요



노드의 꼬리에 추가하는 연결리스트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <stdio.h>
#include <stdlib.h>
 
typedef struct _node
{
  int data;
  struct _node * next;
}Node;
 
int main(void)
{
  // NULL 초기화
  Node * head = NULL;
  Node * tail = NULL;
  Node * cur = NULL;
  Node * newNode = NULL;
 
  // 데이터 입력받는 과정
  int readData;
  while (1)
  {
    printf("자연수 입력: ");
    scanf("%d"&readData);
 
    if (readData < 1)
      break;  
 
    // 노드 생성
    newNode = (Node*)malloc(sizeof(Node));
    newNode->data = readData;
    newNode->next = NULL;
 
    if (head == NULL)
      head = newNode;
    else
      tail->next = newNode;
 
    tail = newNode;
  }  
  // 데이터 출력과정
  printf("\n 전체 데이터 출력: \n");
  if (head == NULL)
    printf("데이터 없음");
 
  else
  {
    cur = head;
    printf("%d ", cur->data);
 
    while(cur->next != NULL)
    {
      cur = (*cur).next;
      printf("%d ", (*cur).data);
    }
  }
  printf("\n");
 
  // 메모리 해제 과정
  if (head == NULL)
    return 0;
 
  else
  {
    Node * delNode = head;
    Node * delNextNode = head->next;    
    printf("%d 삭제 \n", head->data);
    free(delNode);
 
    while (delNextNode != NULL)
    {
      delNode = delNextNode;
      delNextNode = delNode->next;
      printf("%d 삭제 \n", delNode->data);
      free(delNode);      
    }
  }
}
cs




더미 노드 기반, 연결리스트


앞선 예제에서 첫번째 노드는 * head가 가리킨다는 점에서

다른 노드들과 차이가 있었다.


때문에 노드추가, 삭제, 조회하는 방법에 있어 일관성이 없다는 단점이 있었다.

(첫번째 노드와 두번째 이후 노드에 차이가 있다)


이를 해결하기위해 Dummy Node를 추가한다.


처음 추가되는 노드가 구조상 두번째 노드가 되며,

노드 추가, 삭제 및 조회의 과정이 일관된 형태로 구성된다.


LinkedRead.c


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include <stdio.h>
#include <stdlib.h>
 
typedef struct _node
{
    int data;
    struct _node * next;
} Node;
 
int main(void)
{
    Node * head = NULL;
    Node * tail = NULL;
    Node * cur = NULL;
 
    Node * newNode = NULL;
    int readData;
 
    head = (Node*)malloc(sizeof(Node));    // 추가 된 문장, 더미 노드 추가
    tail = head;
    
    /**** 데이터를 입력 받는 과정 ****/
    while (1)
    {        
        printf("자연수 입력: ");
        scanf("%d"&readData);
        if (readData < 1)
            break;
 
        /*** 노드의 추가과정 ***/
        newNode = (Node*)malloc(sizeof(Node));
        newNode->data = readData;
        newNode->next = NULL;
 
        /*
        if(head == NULL)
        head = newNode;
        else
        tail->next = newNode;
        */
        tail->next = newNode;
 
        tail = newNode;
    }
    printf("\n");
 
    /**** 입력 받은 데이터의 출력과정 ****/
    printf("입력 받은 데이터의 전체출력! \n");
    if (head == NULL)
    {
        printf("저장된 자연수가 존재하지 않습니다. \n");
    }
    else
    {
        cur = head;
        //    printf("%d  ", cur->data);   // 첫 번째 데이터 출력
 
        while (cur->next != NULL)    // 두 번째 이후의 데이터 출력
        {
            cur = cur->next;
            printf("%d  ", cur->data);
        }
    }
    printf("\n\n");
 
    /**** 메모리의 해제과정 ****/
    if (head == NULL)
    {
        return 0;    // 해제할 노드가 존재하지 않는다.
    }
    else
    {
        Node * delNode = head;
        Node * delNextNode = head->next;
 
        //    printf("%d을(를) 삭제합니다. \n", head->data);
        //    free(delNode);    // 첫 번째 노드의 삭제
 
        while (delNextNode != NULL)    // 두 번째 이후의 노드 삭제 위한 반복문
        {
            delNode = delNextNode;
            delNextNode = delNextNode->next;
 
            printf("%d을(를) 삭제합니다. \n", delNode->data);
            free(delNode);    // 두 번째 이후의 노드 삭제
        }
    }
 
    return 0;
}
cs


연결리스트를 공부할 땐 그림을 코드로 옮기거나,

코드를 그림으로 옮기는 과정을 거쳐가며 공부하는게 좋다.

728x90