C语言 双链表 插入/删除/查找/遍历/递归/合并/排序

       双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。

1 双链表数据结构

1.1 新增节点图解

C语言 双链表 插入/删除/查找/遍历/递归/合并/排序_第1张图片

1.2 删除一个节点图解

C语言 双链表 插入/删除/查找/遍历/递归/合并/排序_第2张图片

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;
}

最后我们看看程序运行结果:

C语言 双链表 插入/删除/查找/遍历/递归/合并/排序_第3张图片

欢迎各位前来支出程序代码不严谨的地方,以增加代码的健壮性和鲁棒性。

你可能感兴趣的:(Windows,C++,嵌入式开发)