如下是实现双向链表的源代码,主要包括:创建链表、插入结点(头插法、尾插法)、遍历链表、删除结点、排序(插入、快速)、清空链表、主函数(验证函数功能),源代码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #include <unistd.h> //不带头结点的双向链表的操作 //本结构体只是为了实现原理的方便,采用了最简单的元素结构,只有一个int型、前指针pre、后指针next typedef struct NODE { int elem; struct NODE *pre; struct NODE *next; }Node, *pNode; //创建不带头结点的双向链表,创建同时,赋值第一个值 pNode Create() { pNode pHead = (pNode)malloc(sizeof(Node)); if(NULL == pHead) { printf("内存申请失败"); return NULL; } printf("插入结点的值:"); scanf("%d",&pHead->elem); pHead->pre = NULL; pHead->next = NULL; return pHead; } //插入结点函数,头插法 pNode InsertHead(pNode pHead) { pNode temp = (pNode)malloc(sizeof(Node)); if(NULL == temp) { printf("内存申请失败"); return pHead; } printf("插入结点的值:"); scanf("%d",&temp->elem); if(NULL == pHead) { temp->next = NULL; temp->pre = NULL; return temp; } temp->next = pHead; pHead->pre = temp; temp->pre = NULL; return temp; } //插入结点函数,尾插法 pNode InsertTail(pNode pHead) { pNode temp = (pNode)malloc(sizeof(Node)); pNode currentNode = pHead; if(NULL == pHead) { printf("内存申请失败"); return pHead; } printf("插入结点的值:"); scanf("%d",&temp->elem); if(NULL == pHead) { temp->next = NULL; temp->pre = NULL; return temp; } while(currentNode->next != NULL) //找到尾结点 { currentNode = currentNode->next; } currentNode->next = temp; temp->pre = currentNode; temp->next = NULL; return pHead; } //遍历函数 void Traversal(pNode pHead) { if(pHead == NULL) { printf("链表未创建\n"); return ; } while(pHead != NULL) { printf("%d\n",pHead->elem); pHead = pHead->next; } } //删除函数 pNode Delete(pNode pHead) { bool flag = false; //判断是否找到了要删除的结点 if(NULL == pHead) { return pHead; } int elem; printf("要删除的值为:"); scanf("%d",&elem); pNode currentNode = pHead; while(currentNode != NULL) //寻找要删除的结点 { if(currentNode->elem == elem) { flag = true; //找到了要删除的结点,flag = true,并且跳出循环 break; //currentNode即为要删除的结点 } currentNode = currentNode->next; } if(flag) //找到了要删除的结点 { if(NULL == currentNode->pre && NULL == currentNode->next) //删除只有一个结点的链表 { free(currentNode); return NULL; } else if(NULL == currentNode->pre && NULL != currentNode->next) //删除第一个结点,并且该链表不只有一个结点 { currentNode = currentNode->next; currentNode->pre = NULL; free(currentNode->pre); return currentNode; } else if(NULL == currentNode->next) //删除尾结点 { currentNode->pre->next = NULL; free(currentNode); return pHead; } else { currentNode->pre->next = currentNode->next; //删除中间结点 currentNode->next->pre = currentNode->pre; free(currentNode); return pHead; } } else //未找到要删除的结点 { printf("未找到值为%d的结点\n",elem); return pHead; } } //插入排序函数,指针交换 //也可以通过new一个新的头结点,仿照带头结点的单向链表的做法,此方法比较简单 //因为不用考虑插入到最前面的这种情况,有兴趣的可以尝试写一下 pNode SortInsert(pNode pHead) { if(NULL == pHead || NULL == pHead->next) { return pHead; //无头结点、只有头结点、只有一个头结点和一个基本结点,没有意义 } pNode currentNode = pHead; pNode currentNodeBefore = pHead; pNode compareNode = pHead->next; currentNode->next = NULL; compareNode->pre = NULL; pNode compareNodeTemp = NULL; //通过compareNode和currentNode的元素值比较,判断插入位置 while(compareNode != NULL) { currentNode = pHead; compareNodeTemp = compareNode->next; while(currentNode != NULL) { if(currentNode->elem > compareNode->elem) { if(NULL == currentNode->pre) //插入最前面 { compareNode->next = currentNode; currentNode->pre = compareNode; compareNode->pre = NULL; pHead = compareNode; } else //插入两结点中间 { currentNode->pre->next = compareNode; compareNode->pre = currentNode->pre; compareNode->next = currentNode; currentNode->pre = compareNode; } break; } currentNodeBefore = currentNode; currentNode = currentNode->next; } if(NULL == currentNode) //插入尾部 { currentNodeBefore->next = compareNode; compareNode->pre = currentNodeBefore; compareNode->next = NULL; } compareNode = compareNodeTemp; } return pHead; } //插入排序,交换值域,思路和交换指针一样,整体来说,比交换指针域简单 pNode SortInsertNum(pNode pHead) { if(NULL == pHead || NULL == pHead->next) { return pHead; //无结点、只有一个结点,没有意义 } pNode currentNode = pHead; pNode compareNode = currentNode->next; pNode compareNodeTemp; int temp; while(compareNode != NULL) { currentNode = pHead; while(currentNode != compareNode) { compareNodeTemp = compareNode; if(currentNode->elem > compareNode->elem) //找到了插入位置 { temp = compareNode->elem; for(; compareNodeTemp != currentNode; ) //将compareNode之前一直到currentNode的元素值都向后移动一个结点 { compareNodeTemp->elem = compareNodeTemp->pre->elem; compareNodeTemp = compareNodeTemp->pre; } currentNode->elem = temp; } currentNode = currentNode->next; } compareNode = compareNode->next; } return pHead; } //找到尾结点函数,为了快速排序的需要 pNode FindTail(pNode pHead) { if(NULL == pHead || NULL == pHead->next) { return pHead; //无结点、只有一个结点,没有意义 } pNode pTail; pNode currentNode = pHead; while(currentNode->next != NULL) { currentNode = currentNode->next; } pTail = currentNode; return pTail; } //找到分割链表的结点函数,快速排序一部分 pNode Partition(pNode pLow, pNode pHigh) { int key = pLow->elem; while(pLow != pHigh) { while(pLow != pHigh && pHigh->elem >= key) pHigh = pHigh->pre; if(pLow != pHigh) { pLow->elem = pHigh->elem; pLow = pLow->next; } while(pLow != pHigh && pLow->elem <= key) pLow = pLow->next; if(pLow != pHigh) { pHigh->elem = pLow->elem; pHigh = pHigh->pre; } } pLow->elem = key; return pLow; } //快速排序函数,值域交换 //指针域交换太复杂,弗敢想象,you can you up //我在写这个排序过程中,主要是参照数组的快速排序方法,其实原理一样,只是判断条件会有所区别 void SortQuick(pNode pHead, pNode pTail) { pNode pPos; if(pHead != pTail) { pPos = Partition(pHead,pTail); if(pPos != pHead) //pPos如果为头结点,pPos->pre会出现问题 { SortQuick(pHead,pPos->pre); } if(pPos != pTail) //同理 { SortQuick(pPos->next,pTail); } } return ; } //清除链表,释放空间,函数最后调用 void ClearList(pNode pHead) { pNode temp; while(pHead != NULL) { temp = pHead->next; free(pHead); pHead = temp; } } int main(int argc, char const *argv[]) { pNode pHead; pNode pTail; pHead = Create(); pHead = InsertTail(pHead); pHead = InsertTail(pHead); pHead = InsertTail(pHead); pHead = InsertTail(pHead); Traversal(pHead); printf("\n"); pHead = Delete(pHead); pHead = SortInsert(pHead); pHead = SortInsertNum(pHead); pTail = FindTail(pHead); SortQuick(pHead,pTail); Traversal(pHead); ClearList(pHead); return 0; }