如下是实现双向链表的源代码,主要包括:创建链表、插入结点(头插法、尾插法)、遍历链表、删除结点、排序(插入、快速)、清空链表、主函数(验证函数功能),源代码如下:
#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;
}

2万+

被折叠的 条评论
为什么被折叠?



