说明:数组提供了连续内存空间的访问和使用,而链表是对内存零碎空间的有效组织和使用。链表又分为单向链表和双向链表,单向链表仅提供了链表的单方向访问,相比之下,双向链表则显得十分方便。
一.单向链表的节点
如下代码所示,双向链表的节点包含两个指向关系和一个数据空间,两个指向分别连接该节点的上一个和下一个节点,数据类型可以是一个结构体类型,也可以是其他类型。
1 typedef struct node 2 { 3 int data; 4 struct node *pre; 5 struct node *next; 6 }Node;
二.双向链表的创建
头插法和尾插法只看代码比较难以与理解,建议画出插入节点时的链表变化图则会非常容易理解,另外,个人认为头插法较优,因为其插入逻辑一步到位,不像尾插法还需在后面完成双向链表的环状连接。
1.头插法
1 Node * creatList() 2 { 3 Node * head = (Node*)malloc(sizeof(Node)); 4 Node * cur = NULL; 5 head->next = head; 6 head->pre = head; 7 int data; 8 scanf("%d",&data); 9 while(data) 10 { 11 cur = (Node*)malloc(sizeof(Node)); 12 cur->data = data; 13 cur->next = head->next; 14 cur->pre = head; 15 head->next = cur; 16 cur->next->pre = cur; 17 scanf("%d",&data); 18 } 19 return head; 20 }
2.尾插法
1 Node * creatList() 2 { 3 Node * head = (Node*)malloc(sizeof(Node)); 4 Node * phead = head; 5 Node * cur = NULL; 6 phead->next = NULL; 7 phead->pre = NULL; 8 int data; 9 scanf("%d",&data); 10 while(data) 11 { 12 cur = (Node*)malloc(sizeof(Node)); 13 cur->data = data; 14 phead->next = cur; 15 cur->pre = phead; 16 phead = cur; 17 scanf("%d",&data); 18 } 19 //完成回环 20 cur->next = head; 21 head->pre = cur; 22 return head; 23 }
三.双向链表的元素插入(头插法)
插入方法:先让插入的节点有所指向,再考虑指向它的指针,具体插入如下:
1 void insertList(Node * head) 2 { 3 printf("intsert new node:"); 4 int data; 5 scanf("%d",&data); 6 Node * cur; 7 cur = (Node*)malloc(sizeof(Node)); 8 cur->data = data; 9 cur->next = head->next; 10 cur->pre = head; 11 head->next = cur; 12 cur->next->pre = cur; 13 }
四.双向链表的查找
既然是双向链表,其查找方式也应该是是双向查找,比起单向链表的单向查找,双向查找同时从两个方向进行查找,加快了查找的速度。
1 Node * searchList(Node * head,int find) 2 { 3 Node * pClock = head->next; 4 Node * pAntiClock = head->pre; 5 while (pAntiClock != pClock->pre) 6 { 7 if(pClock->data == find) 8 return pClock; 9 if(pAntiClock->data == find) 10 return pAntiClock; 11 if(pClock == pAntiClock) 12 return NULL; 13 pClock = pClock->next; 14 pAntiClock = pAntiClock->pre; 15 } 16 return NULL; 17 }
五.删除某个节点
1 void deleteList(Node * pfind) 2 { 3 if(pfind == NULL) 4 return; 5 else 6 { 7 pfind->pre->next = pfind->next; 8 pfind->next->pre = pfind->pre; 9 free(pfind); 10 } 11 }
六.链表排序(按值排序)
1 void sortList(Node * head,int n) 2 { 3 Node * p,*q; 4 for(int i=0; i<n-1; i++) 5 { 6 p = head->next; 7 q = p->next; 8 for(int j=0; j<n-1-i; j++) 9 { 10 if(p->data > q->data) 11 { 12 p->data = p->data ^ q->data; 13 q->data = p->data ^ q->data; 14 p->data = p->data ^ q->data; 15 } 16 p = p->next; 17 q = q->next; 18 } 19 } 20 }
七.链表的销毁
1 void destroyList(Node * head) 2 { 3 head->pre->next = NULL; 4 Node * pre = head; 5 while(head != NULL) 6 { 7 head = head->next; 8 free(pre); 9 pre = head; 10 } 11 }
说明:链表的操作还有如求长度、打印以及交换指针排序等,由于相对较为简单,此处就不再例举。重要提醒:链表的某些操作较难理解,最好画图加以辅助理解。