您的位置:首页 > 运维架构 > Linux

Linux之链表(一)——初始化、头插、尾插、头删、尾删

2018-04-02 16:54 197 查看
在我们实现初始化、头插、尾插、头删、尾删要先做哪些工作呢?
首先我们要vim 两个文件Linklist.h Linklist.c。
在h文件中写入函数名、结构体等,真正实现的代码在c文件中实现。
1.创建节点的结构体 typedef char LinkNodeType;
5 typedef struct LinkNode
6 {
7     LinkNodeType data;
8     struct LinkNode* next;
9 }LinkNode;
我们编写的是字符型链表,所以节点的结构体中有一个字符型数据,和指向下一个节点的结构体指针。
用一个宏来代替char, 将来方便我们修改与维护。
2.链表初始化 5 void LinklistInit(LinkNode** head)
6 {
7 *head = NULL;
8 }
头指针置为空就行了,该链表为一个空链表。
3.创建节点 17 LinkNode* CreatNode(LinkNodeType value)
18 {
19 LinkNode*new_node = (LinkNode*)malloc(sizeof(LinkNode));
20 new_node -> data = value;
21 new_node -> next = NULL;
22 return new_node;
23 }
创建一个节点,首先要申请空间,申请的大小为整个节点结构体,再将其强转成结构体指针类型。
分别把结构体内的数据、下一个节点的结构体指针设置好,返回new_node这个节点的地址,我们的节点就创建好啦。
4.删除节点 11 void DestroyNode(LinkNode* node)
12 {
13 free(node);
14 }我们申请节点的时候是用malloc申请的,所以当你删除时需要用free进行释放内存,否则会出现内存泄漏的情况。这里我们为什么要用一个函数来封装这一个语句呢?首先,代码逻辑结构紧密,整体具有建筑美。其次,将来我们修改或维护时,只需要对其函数进行修改就可以了,比较方便。
5.打印链表 25 void LinklistPrintChar(LinkNode *head,const char* msg)
26 {
27 printf("[%s]\n",msg);
28 LinkNode* cur = head;
29 for(;cur != NULL; cur = cur->next)
30 {
31 printf("[%c]",cur->data);
32 }
33 printf("\n");
34 }传入msg的目的是:我们可以编写一些说明信息,这一次打印的意义之类的。
定义一个cur当前指针,指向链表头指针,然后对链表进行遍历,打印出data值。循环条件为只要cur不为空,执行printf语句,并cur指向下一个节点cur->next。
准备工作做好以后,现在就可以来实现我们的头插头删、尾插尾删了。
6.头插 85 void LinklistPushFront(LinkNode** head, LinkNodeType value)
86 //insert into head
87 {
88 if (head == NULL)
89 return;
90 LinkNode* new_head = CreatNode(value);
91 new_head->next = *head;
92 //if haven't next code ,then print still from head;
93 *head = new_head;
94 return;
95 }
这个函数传入两个参数,一个是head指针,一个是插入的值。
思路如下:因为要对链表的进行修改,所以我们需要传入二级指针。每一个指针的传入我们都需要检验其合法性。首先判断head,如果head为空,则说明非法传参;再判断*head,如果*head为空,则说明这个链表的一个空链表。我们要实现的是头插,所以不用考虑*head为空的情况,因为插入的步骤与普通情况的步骤一致。
首先创建一个新节点,将新节点的next指向head,最后记得要将head置为new_head;不然打印的时候仍然从head开始,实际上你已经插入了,确看不到现象。



7.头删 97 void LinklistPopFront(LinkNode** head )
98 //delete into head
99 {
100 if (head == NULL)
101 return;
102 if (*head == NULL)
103 return;
104 if ((*head)->next == NULL)
105 {
106
107 DestroyNode(*head);
108 return;
109 }
110 LinkNode* new_head = (*head)->next;
111 DestroyNode(*head);
112 *head = new_head;
113 return;
114 }首先还是对指针的判断。然后考虑两种情况:
1:只有一个节点。那么直接销毁节点就可以了。
2:一个以上的节点。首先你要将头节点保存一份,(如果你直接删除头结点,你就找不到下一个节点了)然后将下一个节点置为头结点。
8.尾插 36 void LinklistPushBack(LinkNode** head,LinkNodeType value)
37 {
38 if(head == NULL)
39 return;
40 if(*head == NULL)
41 {
42 *head = CreatNode(value);
43 return;
44 }
45 LinkNode* cur = *head;
46 for(; cur->next != NULL ; cur = cur->next) ;
47 //LinkNode* new_node = cur->next;
48 //new_node->data = value;
49 //new_node->next = NULL;
50 //or
51 LinkNode* new_node = CreatNode(value);
52 cur->next = new_node;
53 }首先还是对指针的判断。然后考虑两种情况
1:空链表的尾插。就是直接创建节点,返回新节点的地址。
2:普通情况尾插。先找到最后一个不为空的节点。然后创建新节点,将这个不为空的next指向新节点。
9.尾删 56 void LinklistPopBack(LinkNode** head)
57 {
58 //delete in tail
59 if( head == NULL )
60 return;
61 if(*head == NULL)
62 return;
63 if((*head)->next == NULL)
64 {
65 DestroyNode(*head);
66 *head = NULL;
67 }
68 LinkNode* cur = *head;
69 LinkNode* pre = NULL;
70 while(cur->next != NULL)
71 {
72 pre = cur;
73 cur = cur->next;
74 }
75 pre->next = cur->next;
76 DestroyNode (cur);
77 return ;
78
79 }首先还是对指针进行判断。然后考虑两种情况
1:只有一个节点。直接删除,记得把头指针置为空。
2:普通情况。要删除最后一个节点,需要找到上一个节点。用pre保存cur的上一个节点。遍历找到不为空的尾节点,先用pre的next指向cur的next,或者NULL,再删除cur此时的尾节点。



测试代码如下:177 void TestLinklistPushBack()
178 {
179 LinkNode* head;
180 LinklistInit(&head);
181 LinklistPushBack(&head,'a');
182 LinklistPushBack(&head,'b');
183 LinklistPushBack(&head,'c');
184 LinklistPushBack(&head,'d');
185 LinklistPrintChar(head," inset into tail ");
186
187 }
188
189 void TestLinklistPopBack()
190 {
191 LinkNode* head;
192 LinklistInit(&head);
193 LinklistPushBack(&head,'a');
194 LinklistPushBack(&head,'b');
195 LinklistPushBack(&head,'c');
196 LinklistPushBack(&head,'d');
197 LinklistPopBack(&head);
198 LinklistPrintChar(head," delete into tail ");
199
200 }
201
202
203 void TestLinklistPushFront()
204 {
205 LinkNode* head;
206 LinklistInit(&head);
207 LinklistPushBack(&head,'a');
208 LinklistPushBack(&head,'b');
209 LinklistPushBack(&head,'c');
210 LinklistPushBack(&head,'d');
211 LinklistPushFront(&head,'d');
212 LinklistPrintChar(head," inset into head ");
213
214 }
215
216 void TestLinklistPopFront()
217 {
218 LinkNode* head;
219 LinklistInit(&head);
220 LinklistPushBack(&head,'a');
221 LinklistPushBack(&head,'b');
222 LinklistPushBack(&head,'c');
223 LinklistPushBack(&head,'d');
224 LinklistPopFront(&head);
225 LinklistPrintChar(head," delete into head");
226
227 }
270 int main ()
271 {
272
273     TestLinklistPushBack();
274     TestLinklistPopBack();
275     TestLinklistPushFront();
276     TestLinklistPopFront();
280     return 0;
281 }
测试结果如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: