双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。
1.1 新增节点图解
1.2 删除一个节点图解
双链表和单链表在操作主要区别在于插入和删除,双链表需要修改节点两端指针的指向。这里的双链表非循环双链表。所以代码和上一章中的单链表的操作区别不是很大,主要还是在于理解其数据结构,下面请看双链表的源码:
先看头文件doublylist.h
#include
#include
#include
//typedef int DataType;
//定义链表节点
typedef struct node
{
int data; //链表数据
struct node* pPrev; //链表上个节点
struct node* pNext; //链表下个节点
}Node, *pNode;
//创建节点
pNode CreateNode_two(int data );
//遍历链表
void travelList_two(pNode pHead);
//尾插法
void pushBack_two(pNode* pHead, int data);
//尾删法
void popBack_two(pNode* pHead);
//头插法
void pushFront_two(pNode* pHead, int data);
//头删法
void popFront_two(pNode* pHead);
//清空链表
void destoryList_two(pNode pHead);
//获取链表长度
int getListSize_two(pNode pHead);
//查找节点
pNode findNode_two(pNode pHead, int data);
//在某位置后插入数据
void insertNode_two(pNode pPos, int data);
//删除某位置的数据根据节点数据
void deleteNode_bydata_two(pNode* pHead, int data);
//删除某位置的数据节点指针
void deleteNode_bynode_two(pNode* pHead, pNode pos);
//查找中间节点
pNode findMidNode_two(pNode pHead);
//查找倒数第k个节点(要求只能遍历一次)
pNode findKNode_two(pNode pHead,int k);
//倒着打印单链表(递归)
void travelList_TailtoHead_two(pNode pHead);
// 将原链表逆置
void reverse_two(pNode* pHead);
//合并两个有序链表(递归)
pNode mergetwoList_two(pNode pHead1, pNode pHead2);
//冒泡排序
void sortList_two(pNode pHead);
再看doublylist.cpp
#include "doublylist.h"
//创建节点
pNode CreateNode_two(int data )
{
pNode pTemp = (pNode)malloc(sizeof(Node));
pTemp->data = data;
pTemp->pPrev = NULL;
pTemp->pNext = NULL;
return pTemp;
}
//遍历链表
void travelList_two(pNode pHead)
{
pNode pTemp = pHead;
printf("list data is: ");
while (pTemp)
{
printf("%d ", pTemp->data);
pTemp = pTemp->pNext;
}
printf("\n");
}
//尾插法
void pushBack_two(pNode* pHead, int data)
{
if(*pHead == NULL)
{
*pHead = CreateNode_two(data);
}
else
{
pNode pTemp = *pHead;
//找到最后一个存在的节点
while(pTemp->pNext != NULL)
{
pTemp = pTemp->pNext;
}
pTemp->pNext = CreateNode_two(data);
pTemp->pNext->pPrev = pTemp;
}
}
//尾删法
void popBack_two(pNode* pHead)
{
if(*pHead == NULL)
return;
else if((*pHead)->pNext == NULL)
{
free(*pHead);
*pHead = NULL;
return;
}
else
{
pNode pTemp = *pHead;
pNode pPrev = NULL;
while (pTemp->pNext != NULL)
{
pPrev = pTemp;
pTemp = pTemp->pNext;
}
free(pTemp);
pPrev->pNext = NULL;
}
}
//头插法
void pushFront_two(pNode* pHead, int data)
{
if(*pHead == NULL)
{
*pHead = CreateNode_two(data);
}
else
{
pNode pTemp = CreateNode_two(data);
pTemp->pNext = (*pHead)->pNext;
pTemp->pPrev = *pHead;
if (pTemp->pNext != NULL) //这里判断下一个节点是否为空
{
pTemp->pNext->pPrev = pTemp;
}
(*pHead)->pNext = pTemp;
}
}
//头删法
void popFront_two(pNode* pHead)
{
if (*pHead == NULL)
{
return;
}
else if ((*pHead)->pNext == NULL)
{
free(*pHead);
*pHead = NULL;
}
else
{
pNode pTemp = *pHead;
(*pHead) = (*pHead)->pNext;
(*pHead)->pPrev = NULL;
free(pTemp);
}
}
//清空链表
void destoryList_two(pNode pHead)
{
pNode pCur = pHead;
while (pCur)
{
pNode pTemp = pCur;
if (pCur->pNext == NULL)
{
break;
}
pCur = pCur->pNext;
pCur->pPrev = NULL;
free(pTemp);
}
pHead = NULL;
}
//获取链表长度
int getListSize_two(pNode pHead)
{
int count=0;
if (pHead == NULL)
{
return 0;
}
else
{
pNode pTemp = pHead;
while (pTemp)
{
count++;
pTemp = pTemp->pNext;
}
return count;
}
}
//查找节点
pNode findNode_two(pNode pHead, int data)
{
pNode pTemp = pHead;
while(pTemp)
{
if(pTemp->data == data)
return pTemp;
pTemp = pTemp->pNext;
}
return NULL;
}
//在某位置后插入数据
void insertNode_two(pNode pPos, int data)
{
if (pPos == NULL)
{
return;
}
else
{
pNode pTemp = CreateNode_two(data);
//新节点前地址是pos,下一个地址是当前位置的下一个节点地址
pTemp->pNext = pPos->pNext;
pTemp->pPrev = pPos;
pPos->pNext = pTemp;
pTemp->pNext->pPrev = pTemp;
}
}
//删除某位置的数据根据节点数据
void deleteNode_bydata_two(pNode* pHead, int data)
{
if (*pHead == NULL)
{
return;
}
else if((*pHead)->data == data)
{
pNode pTemp = *pHead;
*pHead = pTemp->pNext;
(*pHead)->pPrev = NULL;
free(pTemp);
}
else
{
pNode pTemp = *pHead;
while (pTemp)
{
if(pTemp->pNext->data == data)
{
pNode pdel = pTemp->pNext;
pTemp->pNext->pNext->pPrev = pTemp;
pTemp->pNext = pdel->pNext;
free(pdel);
break;
}
pTemp = pTemp->pNext;
}
}
}
//删除某位置的数据节点指针
void deleteNode_bynode_two(pNode* pHead, pNode pos)
{
if (*pHead == pos)
{
if ((*pHead)->pNext != NULL)
{
pNode pTemp = *pHead;
*pHead = (*pHead)->pNext;
(*pHead)->pPrev = NULL;
free(pTemp);
}
else
{
free(*pHead);
*pHead = NULL;
}
return;
}
else
{
pNode pPrev = *pHead;
while (pPrev)
{
if(pPrev->pNext == pos)
{
if (pos->pNext != NULL)
{
pPrev->pNext = pos->pNext;
pos->pNext->pPrev = pPrev;
}
else
{
pos->pPrev->pNext = NULL;
}
free(pos);
break;
}
pPrev = pPrev->pNext;
}
}
}
//查找中间节点
pNode findMidNode_two(pNode pHead)
{
pNode fast = pHead;
pNode slow = pHead;
while (fast && fast->pNext)
{
fast = fast->pNext->pNext;
slow = slow->pNext;
}
return slow;
}
//查找倒数第k个节点(要求只能遍历一次)
pNode findKNode_two(pNode pHead,int k)
{
pNode fast = pHead;
pNode slow = pHead;
while(fast && k--)
{
fast = fast->pNext;
}
if(k>0) //防止传入的位置与实际链表长度不符合
{
return NULL;
}
while (fast)
{
slow = slow->pNext;
fast = fast->pNext;
}
return slow;
}
//倒着打印单链表(递归)
void travelList_TailtoHead_two(pNode pHead)
{
if (pHead)
{
travelList_TailtoHead_two(pHead->pNext);
printf(" %d ", pHead->data);
}
}
// 将原链表逆置将原先链表的节点取下来,依次采用头插法插入新的链表头下,然后将处理完的地址拷贝到以前的头节点
void reverse_two(pNode* pHead)
{
pNode cur = *pHead;
pNode newHead = NULL;
while (cur)
{
pNode pTemp = cur;
cur = cur->pNext;
pTemp->pNext = newHead;
if (newHead!=NULL) //第一个节点是空的,后面的节点的前节点指向当前节点
{
newHead->pPrev = pTemp;
}
pTemp->pPrev = NULL;
newHead = pTemp;
}
*pHead = newHead;
}
//合并两个有序链表(递归)
pNode mergetwoList_two(pNode pHead1, pNode pHead2)
{
if(pHead1 == NULL)
{
return pHead2;
}
else if (pHead2 == NULL)
{
return pHead1;
}
pNode pMergeHead = NULL;
if (pHead1->data < pHead2->data)
{
pMergeHead = pHead1;
pMergeHead->pNext = mergetwoList_two(pHead1->pNext, pHead2);
pMergeHead->pNext->pNext->pPrev = pMergeHead->pNext;
}
else
{
pMergeHead = pHead2;
pMergeHead->pNext = mergetwoList_two(pHead2->pNext, pHead1);
pMergeHead->pNext->pNext->pPrev = pMergeHead->pNext;
}
return pMergeHead;
}
//冒泡排序
void sortList_two(pNode pHead)
{
if (pHead == NULL)
{
return;
}
int size = getListSize_two(pHead);
for (int i=0;ipNext;
for (int j=0;jdata > right->data) //交换位置
{
int tmp = left->data;
left->data = right->data;
right->data = tmp;
}
right = right->pNext;
left = left->pNext;
}
}
}
再看测试代码,测试代码和上一章基本一致:
#include
#include
#include "doublylist.h"
void test1_two()
{
pNode doublylist = NULL;
//尾插
pushBack_two(&doublylist, 1);
pushBack_two(&doublylist, 2);
pushBack_two(&doublylist, 3);
pushBack_two(&doublylist, 4);
pushBack_two(&doublylist, 5);
pushBack_two(&doublylist, 6);
pushBack_two(&doublylist, 7);
travelList_two(doublylist);
//尾删
popBack_two(&doublylist);
travelList_two(doublylist);
//头插法
pushFront_two(&doublylist, 9);
travelList_two(doublylist);
//头删法
popFront_two(&doublylist);
travelList_two(doublylist);
//
destoryList_two(doublylist);
}
void test2_two()
{
pNode doublylist = NULL;
pushBack_two(&doublylist, 13);
pushBack_two(&doublylist, 11);
pushBack_two(&doublylist, 5);
pushBack_two(&doublylist, 6);
pushBack_two(&doublylist, 7);
pushBack_two(&doublylist, 2);
travelList_two(doublylist);
//查找节点
pNode pos = findNode_two(doublylist, 5);
insertNode_two(pos, 8);
travelList_two(doublylist);
//根据数据删除节点
deleteNode_bydata_two(&doublylist, 5);
travelList_two(doublylist);
deleteNode_bynode_two(&doublylist, findNode_two(doublylist, 8));
travelList_two(doublylist);
//根据位置删除节点
deleteNode_bynode_two(&doublylist, findNode_two(doublylist, 2));
travelList_two(doublylist);
destoryList_two(doublylist);
}
void test3_two()
{
pNode doublylist = NULL;
//尾插
pushBack_two(&doublylist, 1);
pushBack_two(&doublylist, 2);
pushBack_two(&doublylist, 3);
pushBack_two(&doublylist, 4);
pushBack_two(&doublylist, 5);
pushBack_two(&doublylist, 6);
pushBack_two(&doublylist, 7);
travelList_two(doublylist);
//查找节点
pNode tempNode = NULL;
tempNode = findMidNode_two(doublylist);
printf("mid node is = %d\n", tempNode->data);
tempNode = findKNode_two(doublylist, 6);
printf("mid node is = %d\n", tempNode->data);
printf("list reverse is: ");
travelList_TailtoHead_two(doublylist);
printf("\n");
//逆置
reverse_two(&doublylist);
travelList_two(doublylist);
destoryList_two(doublylist);
}
void test4_two()
{
pNode tempNode = NULL;
pNode doublylist1 = NULL;
pNode doublylist2 = NULL;
//尾插
pushBack_two(&doublylist1, 5);
pushBack_two(&doublylist2, 22);
pushBack_two(&doublylist1, 3);
pushBack_two(&doublylist2, 1);
pushBack_two(&doublylist1, 15);
pushBack_two(&doublylist2, 62);
pushBack_two(&doublylist2, 75);
pushBack_two(&doublylist2, 33);
pushBack_two(&doublylist1, 15);
pushBack_two(&doublylist2, 17);
pushBack_two(&doublylist1, 69);
pushBack_two(&doublylist2, 65);
travelList_two(doublylist1);
travelList_two(doublylist2);
tempNode = mergetwoList_two(doublylist1, doublylist2);
travelList_two(tempNode);
sortList_two(tempNode);
travelList_two(tempNode);
destoryList_two(tempNode);
}
int main()
{
test1_two();
printf("----------------------------\n");
test2_two();
printf("----------------------------\n");
test3_two();
printf("----------------------------\n");
test4_two();
system("pause");
return 0;
}
最后我们看看程序运行结果:
欢迎各位前来支出程序代码不严谨的地方,以增加代码的健壮性和鲁棒性。