티스토리 뷰

  • 단일 연결 리스트


 정의

 자료가 배열과 다르게 연속적이지 않으므로, 추가 삽입이 간편하다.

 처음부터 시작해 검색하므로, 중간과 끝에 있는 자료는 찾는데, 시간이 걸린다.

 노드 다음 노드를 가르킨다.

 시작을 항상 가지고 있다.



  • 전체 소스 (런타임 오류 투성이)
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*##################################
단일연결리스트(수업용)
파일명: LinkedList_empty.cpp
작성자: 김홍규 강사님
마지막수정날짜: 2018.04.10
버전: 1.05
###################################*/
 
#include <stdio.h>
#include <stdlib.h> //메모리 동적할당 헤더
#include <crtdbg.h> //메모리 누수 탐지 헤더
//#include  "linkedlistClass.h"
 
struct SNode {
    int nData;
    SNode* pNext;
};
 
SNode* CreateNode(SNode* pNode, int data);
SNode* FindNodeData(SNode* pStart, int data);
SNode* InsertNodeData(SNode* pStart, int data, int insert);
void DeleteNodeData(SNode* pStart, int del);
void PrintLinkedList(SNode* pStart);
void DeleteLinkedList(SNode* pStart);
void ReverseLinkedList(SNode* pStart);
 
 
void InputAdd();
 
//정상작동 테스트를 위해서, 다음과 같이 기본적인 절차로 오류를 확인한다.
//이 소스에 몇가지 버그가 존재한다.
//이 코드가 정상작동 된 후 발견해볼것!
//main()함수 내 코드는 절대 코드 변경하지말것.
void main()
{
    //_CrtSetBreakAlloc(71); //메모리 누수시 번호를 넣으면 할당하는 위치에 브레이크 포인트를 건다.
    //_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); //메모리 누수 검사 
 
    SNode* pBegin = NULL;
    SNode* pEnd = NULL;
 
 
    pEnd = CreateNode(pEnd, 10);
    pBegin = pEnd;
 
    pEnd = CreateNode(pEnd, 20);
    pEnd = CreateNode(pEnd, 30);
    pEnd = CreateNode(pEnd, 40);
    pEnd = CreateNode(pEnd, 50);
 
    PrintLinkedList(pBegin);
 
    SNode* pFind = FindNodeData(pBegin, 40);
    printf("Find:%d\n", pFind->nData);
 
    pEnd = InsertNodeData(pBegin, 3060);
 
    PrintLinkedList(pBegin);
 
    DeleteNodeData(pBegin, 60);
 
    PrintLinkedList(pBegin);
 
    DeleteLinkedList(pBegin);
}
 
//여기서 부터 기능을 구현한다.
//기존코드는 손대지말고, 추가만 하여 현 프로그램 정상 작동하도록할것.
SNode* CreateNode(SNode* pNode, int data)
{
    SNode* pTemp = NULL;
 
    pTemp = new SNode();
    pTemp->nData = data;
 
    return  pTemp;
}
 
SNode* FindNodeData(SNode* pStart, int data)
{
    SNode* pNode = pStart;
 
    return pNode;
}
 
SNode* InsertNodeData(SNode* pStart, int data, int insert)
{
    SNode* pNode = pStart;
 
    pNode = FindNodeData(pStart, data);
 
    return pNode;
}
 
void DeleteNodeData(SNode* pStart, int del)
{
    SNode* pPre = NULL;
    SNode* pNode = pStart;
 
 
}
 
void PrintLinkedList(SNode* pStart)
{
    SNode* pNode = pStart;
    printf("data:");
    while (pNode)
    {
        printf("%d", pNode->nData);
        pNode = pNode->pNext;
 
        if (pNode != NULL)
            printf(",");
    }
    printf("\n");
}
 
void DeleteLinkedList(SNode* pStart)
{
    SNode* pNode = pStart;
    SNode* pDel = NULL;
}
 
void InputAdd()
{
    SNode* pStart = NULL;
    SNode* pNode = NULL;
    int nData = 0;
 
    //동적할당을 하면 프로그램이 사용자에 의해서 사용되는 메모리가 결정된다.
    //쉽게말해서, 컴파일단계에서 100개를 만들고 쓴다면, 
    //사용하지않더라도 100개의 메모리를 사용할수밖에없다.
    //그리고, 100개 이상의 메모리도 사용할수없다.
    //그러나, 동적할당을 하면 사용자가 추가한 메모리만큼만 메모리가 사용되고 
    //메모리용량이 허용하는 한 추가가 된다.
    while (nData != -1)
    {
        scanf("%d"&nData);
        pNode = CreateNode(pNode, nData);
 
        if (pNode == NULL)
        {
            printf("더 이상 사용할수 있는 메모리가 없습니다!");
        }
 
        if (pStart == NULL)
            pStart = pNode;
 
        PrintLinkedList(pStart);
    }
 
    DeleteLinkedList(pStart);
}
cs


우선 각각의 의미를 가지고 있는 함수들이 있습니다. CreateNode는 생성, FindNodeData는 찾기, InsertNodeData는 삽입 그리고 DeleteNodeData는 삭제의 의미를 가지고있습니다. 물론 다른 함수들도 각자의 의미를 가지고 있습니다.

하지만 런타임 오류 투성이죠. CreateNode로 새로운 노드를 생성하지만 연결이 되지않아 시작 노드의 data만 읽어지거나, FindNodeData로 특정 노드를 찾지만 안찾아진다거나, InsertNodeData로 특정 노드를 삽입 할려지만 삽입이 안되고 DeleteNodeData로 특정 노드 삭제를 할려지만 삭제가 안되죠.

이 코드가 정상작동 하도록 고치는 것이 목표입니다. 단일 연결리스트에는 몇 가지 조건이 있습니다. main()함수를 수정해서 고치면 안됩니다. 그 밖에는 주석으로 표시해두었습니다.

전체 코드를 보았으니 이제 코드를 해석해봅시다. C언어는 main() 함수부터 번역합니다.



  • 연결 리스트 생성

void main()
{
    //_CrtSetBreakAlloc(71);
    //_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
 
    SNode* pBegin = NULL;
    SNode* pEnd = NULL;
 
    pEnd = CreateNode(pEnd, 10);
cs


pBegin, pEnd를 NULL 값으로 생성하고 있습니다. 어떤식으로 생성되는 걸까요? SNode* 함수로 가봅시다.




struct SNode {
    int nData;
    SNode* pNext;
};
cs

SNode는 구조체(struct)이고 정수형 데이터 타입(int)을 가지면서 포인터값(*)으로 자기 자신을 이어받는군요? 이어받는 다는 표현이 맞는지는 모르겠네요.

구조체(struct)를 저렇게 만든 이유는

연결(Link)을 생각하시면 편합니다. 포인터(*)로 주소값을 이어서 서로 서로 연결하는 것이죠. 그렇다면 이 소스는 아래 사진처럼 됩니다.

강사님 말로는 d 구조체에 next가 아니라 NULL이 들어간다고 합니다. 여기서 각 노드마다 0x00, 0x01 와 같이 주소형태로 적는 것은 동적할당으로 노드를 생성했을 시 변수 이름을 가지지 않고 주소만 가지기 때문에 저런 형태로 나타냅니다.


그러므로 


    SNode* pBegin = NULL;
    SNode* pEnd = NULL;
cs
해당 소스들은 구조체에 NULL값이 들어가므로 

이렇게 됩니다. 이걸 그림으로 나타내면


이렇게 됩니다. SNode*는 포인터 구조체라는 걸 인지해야 합니다.



이제 계속해서 main()함수를 읽어 내려가보겠습니다.


    pEnd = CreateNode(pEnd, 10);
    pBegin = pEnd;
cs

CreateNode 매개변수로 pEnd와 데이터 10을 받는군요. 그럼 CreateNode 함수를 읽어봅시다.




SNode* CreateNode(SNode* pNode, int data)
{
    SNode* pTemp = NULL;
 
    pTemp = new SNode();
    pTemp->nData = data;
 
    return  pTemp;
}
cs

이걸 그대로 번역해서 그림으로 그려보자면


pTemp함수가 이런식으로 생기게되고 return 값으로 pTemp를 반환하고 pEnd로 대입하므로 pEnd는 pTemp의 주소값을 받습니다. 물론 CreateNode의 중괄호를 벗어나서 main()함수로 돌아가면 pTemp라는 함수는 사라집니다. 하지만 pEnd의 주소값을 따라가면 10도 받을 수 있습니다.



    pEnd = CreateNode(pEnd, 10);
    pBegin = pEnd;
 
    pEnd = CreateNode(pEnd, 20);
    pEnd = CreateNode(pEnd, 30);
    pEnd = CreateNode(pEnd, 40);
    pEnd = CreateNode(pEnd, 50);
cs

main()함수에 있는 CreateNode를 다 그려보겠습니다.


CreateNode(pEnd, 50)까지 다 했을 때 그림입니다. pBegin이 0x01인 이유는 pEnd가 0x01일때 대입받기 때문입니다. 즉, 단일 연결 리스트의 시작지점을 pBegin에 저장해놓는 것입니다.

그런데 이건 잘못된 코드입니다. 여기서 문제점은 무엇일까요? 바로 pTemp가 새로 만들어질 때마다 연결이 안되는 것입니다. 연결이 안되면 0x01에서 그 다음 노드로 갈 수가 없으므로 CreateNode는 잘못된 코드입니다.


연결한 모습은 이렇게 되겠죠?

그렇다면 연결할려면 어떻해야 할까요? 우선 생성된 노드들을 연결하기 위해선 2개 이상의 노드가 필요합니다. 1개만 있을때는 당연히 연결할 수 없습니다. 또한 그 다음 노드의 주소값을 알아야합니다. 이전 노드와 다음 노드의 주소값을 연결시키는 pNext에 그 다음 노드의 주소를 넣으면 연결되는 것이죠.

pNode가 2개 만들어진 상황을 예시로 들어보겠습니다. 0x01과 0x02를 잇기 위해서는 0x02의 주소를 알아야겠죠? 2개의 pNode가 만들어졌을 때 0x02의 주소값은 pTemp입니다. 왜냐하면 CreateNode 코드에서 pTemp로 pNode를 생성하기 때문입니다.

그러므로 알맞은 코드는 이렇게 됩니다.


SNode* CreateNode(SNode* pNode, int data)
{
    SNode* pTemp = NULL;
 
    pTemp = new SNode();
    pTemp->nData = data;
 
    if (pNode != NULL)
    {
        pNode->pNext = pTemp;
    }
 
    return  pTemp;
}
cs
조건으로 [pNode가 NULL이 아닐 때]를 주었습니다. 왜냐하면 pNode는 매개변수로 pEnd의 값을 받아오고 pEnd는 CreateNode가 끝날 때 pTemp를 반환 받으므로 이전 CreateNode의 pTemp의 주소값을 가집니다.

그리고 이전 노드(pNode)와 현재 노드를 잇기 위해서는 이전 노드의 pNext에 현재 노드의 주소값을 넣어야합니다. 현재 노드는 pTemp이므로 조건문안에 코드는 그림과 같이 됩니다.


물론 이미 해보셨겠지만, 결과가 어떻게 달라지는지 콘솔창에서 보겠습니다.

변경 전

변경 후

main()함수의 PrintLinkedList(pBegin)를 읽으면서 0x01의 주소에 연결되있는 0x05까지의 data가 모두 출력되었습니다.

물론 아직 완전한 코드가 아닙니다. 이제 FindNodeData를 고칠 차례입니다! 같이 고쳐봅시다.



  • 특정 노드 찾기

    SNode* pFind = FindNodeData(pBegin, 40);
    printf("Find:%d\n", pFind->nData);
cs

FindNodeData(pBegin, 40)의 함수 이름을 보면 의미를 알 수 있습니다. pBegin에 연결되있는 노드들 중 40을 찾는다는 의미입니다.

하지만 현재 콘솔창을보면 10이 되어있습니다. pBegin 첫 노드의 data가 10이 들어있던걸 생각하면 40을 못찾았다고 할 수 있겠죠.


현재 잘못된 코드인 FindNodeData를 보러 가봅시다.



SNode* FindNodeData(SNode* pStart, int data)
{
    SNode* pNode = pStart;
 
    return pNode;
}
cs

FindNodeData의 매개변수 pStart는 pBegin을 받습니다. 그러므로 pNode는 pBegin과 같습니다. 하지만 매개변수 data가 40 이었지만 10을 출력했죠.

현재 10을 출력한 이유는 노드들이 연결은 되어있지만 다음 노드로 못가기 때문입니다. data 40이 될때까지 다음 노드로 넘어가야되는데 현재 코드는 그게 안되는 것이죠. 즉, 현재 코드는 0x01의 data만 출력합니다.


우리가 원하는 data는 40입니다. 40 data를 가진 노드로 이동할 때 까지 연결된 주소값을 따라가야합니다.

즉, 노드 하나 하나를 처음부터 확인하면서 data 40일때 멈추는 코드를 짜야합니다.


SNode* FindNodeData(SNode* pStart, int data)
{
    SNode* pNode = pStart;
 
    while (pNode != NULL)
    {
        if (pNode->nData != data)
        {
            pNode = pNode->pNext;
        }
        else
            return pNode;
    }
 
    return pNode;
}
cs

반복문 while안에 조건문 if을 주었습니다. 반복문의 조건은 [pNode가 NULL이 아닐 때]입니다. 0x05의 pNext가 NULL이므로 0x05가 될때까지 문제없이 반복하겠죠. 조건문의 조건은 pNode의 data가 40이 아닐때 pNode의 주소를 pNext로 바꿔주는 주소입니다. 즉, 다음 노드로 이동된다는 말이죠.

이해가 되지 않는다면 아래 그림을 찬찬히 보면 됩니다.

pNext에 다음 노드의 주소값이 들어가면 다음노드로 이동되므로 다르게 생각해보면 pNode의 주소가 pNext의 값이 들어간다면 다음 노드로 이동할 수 있겠죠.

그러므로 if 조건문처럼 조건을 주면 반복문으로 연결 리스트가 반복되면서 다음 노드로 계속 이동되는 것이죠.


정상적으로 FindNodeData(pBegin, 40)이 읽어집니다!


하지만 아직 코드가 틀렸습니다. main()함수를 계속 읽어봅시다.




  • 특정 노드 삽입

    pEnd = InsertNodeData(pBegin, 30, 60);
 
    PrintLinkedList(pBegin);
cs

InsertNodeData 함수는 삽입한다는 의미입니다. pBegin 연결 리스트에 30 data 노드 다음에 60 data 노드를 연결시키는 것이죠.


하지만 현재 콘솔창을 보면 30 data 다음에 60이 안나오고 40이 나오죠.


InsertNodeData 함수를 고쳐야하므로 보러가봅시다.



SNode* InsertNodeData(SNode* pStart, int data, int insert)
{
    SNode* pNode = pStart;
 
    pNode = FindNodeData(pStart, data);
 
    return pNode;
}
cs

현재 InsertNodeData를 보면 FindNodeData가 쓰입니다.

왜 그럴까요? 그 이유는 삽입할려는 부분의 이전 노드를 알아야 되기 때문입니다.


저희는 30 data 다음에 60을 넣을려고 하고있습니다. 그렇다면 그림을 다시 그려보겠습니다.


우선 data 60의 노드를 생성해야겠죠? data 60을 가진 노드가 없는데 생길 일은 없으니까요. 그렇다면 생성되있는 노드들은 해당그림처럼 됩니다. 우선 이걸 코드로 옮겨봅시다.



SNode* InsertNodeData(SNode* pStart, int data, int insert)
{
    SNode* pNode = pStart;
    SNode* pTemp = NULL;
 
    pTemp = new SNode();
    pTemp->nData = insert;
 
    pNode = FindNodeData(pStart, data);
 
    return pNode;
}
cs

pTemp로 새로운 포인터 구조체를 만들었고 data에 insert(60)을 넣었습니다. 그러므로 위에 그린 표처럼 된 것입니다.

그럼 이제 새로만든 pTemp를 30과 40사이에 넣어야합니다. CreateNode를 이해하신 분은 어떻게 넣을지 감이 오실 것입니다. 왜냐하면 비슷한 방식이기 때문이죠.


pTemp의 pNext가 NULL이었는데, 0x04가 되었습니다. 그렇게 되야 연결되니까요! CreateNode처럼 이전 노드의 pNext에 다음 노드의 주소값을 대입(연결)한다는 개념이 어렵지 CreateNode를 이해하고 그림을 그려본다면 금방 이해할 수 있습니다.

하지만 문제가 있습니다. 어느 시점때 pTemp의 pNext에 0x04를 넣을 수 있고 0x03의 pNext에 0x06을 언제 넣어야될까요?

이 문제를 고민해야되는 이유는 pNode의 각각의 노드들은 엄밀히 말하면 각자의 구조체(이렇게 설명해도 될지는 모르겠음)입니다. 각 노드를 이동 할때마다 사용할 수 있는 주소값(pNext)과 데이터(data)가 항상 다르죠.


우리가 필요한 정보들은, 0x06의 pNext가 NULL이므로 0x04로 바꾸기 위해 0x04가 필요하죠. 그리고 0x03의 pNext에 0x04가 아니라 0x06이 들어가야 pTemp와 연결되겠죠.

즉, 우리가 필요한 정보는 0x04와 0x06입니다.


우선 그림을 그려서 머리속에 정리했으니 코드로 바꿔봅시다.



SNode* InsertNodeData(SNode* pStart, int data, int insert)
{
    SNode* pNode = pStart;
    SNode* pTemp = NULL;
 
    pTemp = new SNode();
    pTemp->nData = insert;
 
    pNode = FindNodeData(pStart, data);
 
    0x06->pNext = 0x04;
    0x03->pNext = 0x06;
 
    return pNode;
}
 
cs

그림에 적혀있는대로 코드에 적어봤습니다. 머리속에 정리가 잘 안될때는 이런식으로 그림에 적혀있는대로 코드를 적어보면 더 잘 적힌다고 강사님이 가르쳐주셨습니다.

앞서 FindNodeData가 왜 쓰이는지 이해하였고 우리는 pNode가 data 30을 가지는 pNode부터 시작한다는 걸 알 수 있습니다. 즉, pNode는 현재 0x03입니다. 이해가 잘 안된다면 FindNodeData를 이해하지 못했다는 뜻입니다. FindNodeData를 사용한 이유는 뒤에서 그림으로 명확히 설명드리겠습니다.

0x06은 당연히 pTemp입니다. 0x04는 0x03의 pNext입니다. 코드 순서를 위 코드처럼 작성한 것은 0x03의 pNext에 0x06을 먼저 대입하면 0x04를 찾을수가 없습니다. 물론 다른 방법이 있겠지만 그건 여러분들이 알아서 찾아보세요!

이걸 C언어로 바꾸어 봅시다.



SNode* InsertNodeData(SNode* pStart, int data, int insert)
{
    SNode* pNode = pStart;
    SNode* pTemp = NULL;
 
    pTemp = new SNode();
    pTemp->nData = insert;
 
    pNode = FindNodeData(pStart, data);
 
    pTemp->pNext = pNode->pNext;
    pNode->pNext = pTemp;
 
    return pNode;
}
cs

그림을 그린 이후에 그림에 나와있는 정보를 토대로 C언어를 작성하면 훨씬 쉽게 작성할 수 있습니다.

0x06은 pTemp입니다. 왜냐하면 pTemp가 new SNode()로 새로 만들어지면서 0x06(엄밀히 말하면 아니지만 6번째 이니까 0x06의 주소값을 가진다고 생각합시다)이 됩니다. SNode()는 포인터 구조체이기 때문이죠.

0x04는 pNode의 pNext입니다. 왜냐하면 FindNodeData(pStart, data)는 FindNodeData(pBegin, 30)입니다.


그림으로 명확히 설명하자면 FindNodeData(pBegin, 30)을 pNode에 대입했으므로 pNode는 현재 위 그림과 같은 상태입니다. 그러므로 0x04는 pNode의 pNext가 됩니다.

0x03은 pNode이므로 C언어로 번역하면 위 코드처럼 됩니다.


현재 콘솔창을 보면 30과 40사이에 60이 들어간걸 알 수 있습니다. 


main()함수에서 InsertNodeData(pBegin, 30, 60)을 pEnd에 대입하였으므로 pEnd는

위 그림처럼 노드가 형성됩니다.

디버깅을 해보면 정말로 pEnd의 노드가 바뀌었는데, 왜 저런식으로 대입을 했는지는 아직까진 모르겠습니다. 강사님께 질문을 해봐야겠습니다. pEnd는 끝을 가리키는 뜻이기 때문에 0x05를 가리키는게 맞는데 강사님이 배포해주신 코드는 저런식으로 pEnd가 바뀌었네요.

pEnd에 대입하는 걸 그대로 지우면 되는 부분이지만 아직 제가 해결하지 못한 DeleteLinkedList와 연관이 있을 수 있기 때문에 아직은 건들이지 않았습니다.


어쨌든 아직까지 완성된 코드는 아닙니다. 



  • 특정 노드 삭제

    DeleteNodeData(pBegin, 60);//노드 삭제
 
    PrintLinkedList(pBegin);
cs

DeleteNodeData(pBegin, 60)는 data 60을 가지고 있는 노드를 삭제한다는 의미로 해석가능합니다. 하지만 콘솔창을 보면 60이 그대로 연결되어있습니다.


void DeleteNodeData(SNode* pStart, int del)
{
    SNode* pPre = NULL;
    SNode* pNode = pStart;
 
 
}
cs

해당 DeleteLinkedList의 현재 코드를 보고 그림으로 나타내보겠습니다.


현재 DeleteLinkedList의 코드를 그림으로 나타내면 이렇습니다. pPre 라는 노드를 NULL 값으로 만들었고(없다는 뜻), 없애는 목표 노드가 60 data를 가진 노드입니다.

이걸 없앨려면은 InsertNodeData 에서 서로의 주소값을 연결했듯이 30 data를 가지는 노드와 40 data를 가지는 노드를 서로 이어주면 됩니다.


그렇게 되면 pNode의 data 60은 없어지게(Delete) 되는거죠.

저희가 생각을 해야되는 문제는 InsertNodeData 때와 마찬가지로 [반복문을 읽을 때 어느 시점에서 멈춰야하는가?]입니다. 반복문을 쓰는 이유는 당연히 CreateNode를 하시면서 아실거라고 생각됩니다. 저희가 반복문을 멈춰야 하는 지점은 0x03의 pNext에 0x04를 집어넣을 수 있는 노드입니다.

그렇다면 이걸 코딩으로 옮겨보겠습니다.


void DeleteNodeData(SNode* pStart, int del)
{
    SNode* pPre = NULL;
    SNode* pNode = pStart;
 
    while (pNode != NULL)
    {
 
        if (pNode->nData == del)
        {
            pPre->pNext = pNode->pNext;
            break;
        }
        else
        {
            pPre = pNode;
        }
 
        pNode = pNode->pNext;
    }
}
cs

0x03의 pNext 와 0x04는 단일 연결리스트로는 두개의 값을 동시에 볼 수 없습니다. 그러므로 pPre라는 노드를 새로 만든 것입니다.

반복문으로 pNode가 읽히면서 조건문(if)의 조건으로 [pNode의 data가 del(60)과 같을 때]라는 조건을 주었습니다. 왜냐하면 위에 있는 그림들을 보면 알겠지만 0x04를 가지고 있기 때문입니다.

그렇다면 0x03의 pNext는 어떻게 구했을까요? 바로 조건문(if)의 조건에 해당하지 않을 시 pPre 노드에 pNode를 대입하고 있습니다.


반복문을 읽고있기 때문에 pNode의 data 가 60이 되었을 때 pPre는 위 사진처럼 노드가 형성되어 있죠. 즉, 조건문(if)의 조건에 맞아떨어 질 때 pPre 노드에 있는 0x03과 pNode 노드에 있는 0x04가 둘다있는 상황이 되죠.

        if (pNode->nData == del)
        {
            pPre->pNext = pNode->pNext;
            break;
        }
cs
그렇기 때문에 조건문의 코드를 읽어보자면 pPre->pNext(0x03의 pNext) = pNode->pNext(0x04)가 됩니다. 0x03의 pNext에 0x04를 대입하였죠.

그렇다면 이런 상태가 됩니다. 0x06을 지우는 방법은 공부를 더 해봐야 할 것 같습니다(ㅋㅋㅋ).

해당 코드가 맞는 코드인지 헤깔린다면, printf 출력함수로 직접 확인해보면 됩니다.



void DeleteNodeData(SNode* pStart, int del)
{
    SNode* pPre = NULL;
    SNode* pNode = pStart;
 
    while (pNode != NULL)
    {
        printf("pNode data: %d\n", pNode->nData);
        printf("pNode p: %d\n", pNode->pNext);
        if (pNode->nData == del)
        {
            pPre->pNext = pNode->pNext;
            break;
        }
        else
        {
            pPre = pNode;
            printf("pPre data: %d\n", pPre->nData);
            printf("pPre p: %d\n", pPre->pNext);
        }
 
        pNode = pNode->pNext;
    }
}
cs
printf 출력 함수를 이용해 pNode 의 data와 pNext 주소값과 pPre 의 data와 pNext 주소값이 일치하는지 직접 출력해서 알아보는 코드입니다.

결과를 보면 data와 pNext모두 일치하는 것을 볼 수 있습니다.

수고하셨습니다. 단일 연결리스트의 생성, 찾기, 삽입과 삭제를 완료하였습니다.

댓글