单链表

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单链表相关的知识,希望对你有一定的参考价值。

    单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。

1、链接存储方法

链接方式存储的线性表简称为链表(LinkList)。

链表的具体存储表示为:

① 用一组任意的存储单元来存放线性表的结点(这组存储单元既可以是连续的,也可以是不连续的)

② 链表中结点的逻辑次序和物理次序不一定相同。为了能正确表示结点间的逻辑关系,在存储每个结点值的同时,还必须存储指示其后继结点的地址(或位置)信息(称为指针(pointer)或链(link))

注意:

链式存储是最常用的存储方式之一,它不仅可用来表示线性表,而且可用来表示各种非线性的数据结构。

2、链表的结点结构

┌───┬───┐

│data │next │

└───┴───┘

data域--存放结点值的数据域

next域--存放结点的直接后继的地址(位置)的指针域(链域


//功能

//LinkList.h

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int DataType;

typedef struct LinkNode	//节点 = 数据 + 指向下一个节点的指针
{
	DataType data;
	struct LinkNode *next;
}LinkNode,*pLinkNode,*pLinkList;

void InitLinkList(pLinkList* pHead);							//初始化链表
void Destroy(pLinkList* pHead);									//销毁链表
pLinkNode BuyNode(DataType x);										//创建一个节点
void PushBack(pLinkList *pHead, DataType x);			//尾插
void PopBack(pLinkList *pHead);									//尾删
void PushFront(pLinkList *pHead, DataType x);		// 头插
void PopFront(pLinkList *pHead);									//头删
void PrintList(pLinkList List);									//打印链表

int GetListLength(pLinkList Head);													//求取链表长度
pLinkNode Find(pLinkList Head, DataType x);								//找指定元素x
void Insert(pLinkList *pHead, pLinkNode pos, DataType x);	//在指定位置pos插入指定元素x
void Erase(pLinkList *pHead, pLinkNode pos);								//删除指定位置pos元素
void Remove(pLinkList* pHead, DataType x);									//删除指定元素x
void RemoveAll(pLinkList* pHead, DataType x);							//删除所有的指定元素x

void EraseNotTail(pLinkNode pos);         // 删除无头链表的非尾节点
void ReverseList(pLinkNode *pHead);	  // 逆序链表
void BubbleSort(pLinkList *pHead);			//排序链表(冒泡)
void InsertFrontNode(pLinkNode pos, DataType x);  //在当前节点前插入一个数据x
pLinkNode Merge(pLinkList list1, pLinkList list2);	  //合并两个有序链表
pLinkNode JosephCycle(pLinkList* pHead, int num);    //约瑟夫环
pLinkNode FindMidNode(pLinkList pHead);	//查找链表的中间节点---7
// 删除单链表的倒数第k个节点(k > 1 && k < 链表的总长度)----9
// 时间复杂度O(N)
void DelKNode(pLinkList *pHead, int k);

// 【链表带环问题】-----10
// 判断链表是否带环, 若链表带环则求环的长度和相遇节点,不带环返回-1
pLinkNode CheckCycle(pLinkList pList);
int GetCircleLength(pLinkNode meet);

// 获取环入口点
pLinkNode GetCycleEntryNode(pLinkList list, pLinkNode meetNode);

// 【链表相交问题】
//
// 判断两个链表是否相交,假设两个链表都不带环。
//
int CheckCross(pLinkList list1, pLinkList list2);


//功能实现

//LinkList.c

#include "LinkList.h"				

void InitLinkList(pLinkList* pHead)	//初始化链表
{
	assert(pHead);
	*pHead = NULL;
}
void Destroy(pLinkList* pHead)		//销毁链表
{
	pLinkNode cur = *pHead;
	assert(pHead);
	if(*pHead == NULL)
	{
		return;
	}
	else
	{
		while(cur)
		{
			pLinkNode del = cur;
			cur = cur->next;
			free(del);
			del = NULL;
		}
	}
}
pLinkNode BuyNode(DataType x)			 //创建一个节点
{
	pLinkNode NewNode = (pLinkNode)malloc(sizeof(LinkNode));
	NewNode->data = x;
	NewNode->next = NULL;
	return NewNode;
}
void PushBack(pLinkList *pHead, DataType x)	 //尾插
{							
	pLinkNode NewNode = BuyNode(x);
	pLinkNode cur = *pHead;
	assert(pHead);
	if(cur == NULL)
	{
		*pHead = NewNode;
	}
	else
	{
		while(cur->next)
		{
			cur = cur->next;
		}																
		cur->next = NewNode;
	}
}
void PopBack(pLinkList* pHead)//尾删
{
	pLinkNode cur = *pHead;
	assert(pHead);
	//没有节点
	if(*pHead == NULL)
	{
		return;
	}
	//一个节点
	else if((*pHead)->next == NULL)
	{
		free(*pHead);
		*pHead = NULL;
	}
	//两个及以上
	else
	{
		pLinkNode del;
		while(cur->next->next)
		{
			cur = cur->next;
		}
		del = cur->next;															 
		cur->next = NULL;
		free(del);
		del = NULL;
	}
}
void PushFront(pLinkList *pHead, DataType x)  //头插
{
	pLinkNode NewNode = BuyNode(x);
	assert(pHead);
	if(*pHead == NULL)
	{
		*pHead = NewNode;
	}
	else
	{
		NewNode->next = *pHead;
		*pHead = NewNode;
	}	
}
void PopFront(pLinkList *pHead)	//头删
{
	assert(pHead);
	if(*pHead == NULL)
	{
		return;
	}
	else
	{
		pLinkNode del = *pHead;
		*pHead = (*pHead)->next;
		free(del);
		del = NULL;
	}
}
void PrintList(pLinkList List)     //打印链表
{
	pLinkNode cur = (pLinkNode)List;
	printf("List is:");
	while(cur)
	{
		printf("%d->",cur->data);
		cur = cur->next;
	}
	printf("over\n");
}
int GetListLength(pLinkList Head)	  //求取链表长度
{
	int count = 0;
	pLinkList cur = Head;
	assert(Head);
	while(cur)
	{
		count++;
		if(cur->next == NULL)
		{
			return count;
		}			
		cur = cur->next;
	}				
	return count;
}
pLinkNode Find(pLinkList Head, DataType x)  //查找指定元素x的位置
{
	pLinkList cur = Head;
	assert(Head);
	while(cur)
	{
		if(cur->data == x)
		{
			return (pLinkNode)cur;
		}
		cur = cur->next;
	}
	return NULL;
}
void Insert(pLinkList *pHead, pLinkNode pos, DataType x)   //指定位置pos插入元素x
{
	pLinkNode cur = *pHead;
	pLinkNode NewNode =BuyNode(x);
	assert(pHead);
	assert(pos);
	while(cur->next != pos)
	{
		cur = cur->next;
	}
	NewNode->next = cur->next;
	cur->next = NewNode;
}

void Erase(pLinkList *pHead, pLinkNode pos)	//删除pos位置元素
{
	pLinkNode cur = *pHead;
	pLinkNode del = NULL;
	pLinkNode prev = NULL;	 //cur的前一个节点
	assert(pHead);
	assert(pos);
	if (cur == NULL)
	{
		printf("List is empty!!\n");
		return;
	}
	while(cur)
	{
		del = cur;
		if (cur == pos)
		{
			//没有节点
			if(cur == *pHead)
			{
				*pHead = (*pHead)->next;
			}
			//一个及以上节点
			else
			{
				prev->next = cur->next;
			}
			free(del);
			del = NULL;
			break; //删除完成后,跳出Erase()
		}
		prev = cur;
		cur = cur->next;
	}
}
void Remove(pLinkList* pHead, DataType x)	//删除元素x
{
	pLinkNode cur = *pHead;
	pLinkNode del = NULL; 
	pLinkNode prev = NULL;//cur的前一个节点
	assert(pHead);
	if(cur == NULL)
	{
		printf("List is empty!!\n");
		return;
	}
	while(cur)
	{
		del = cur;
		if(cur->data == x)
		{
			//没有节点
			if(cur == *pHead)
			{
				*pHead = (*pHead)->next;
			}
			//一个及以上节点
			else
			{
				prev->next = cur->next;
			}
			free(del);
			del = NULL;
			break;	//只删除一次,删除后跳出Remove()
		}
		prev = cur;
		cur = cur->next;
	}
}
void RemoveAll(pLinkList* pHead, DataType x)   //删除所有的元素x
{
	pLinkNode cur = *pHead;
	pLinkNode del = NULL;
	pLinkNode prev = NULL;	 //cur的前一个节点
	assert(pHead);
	if(cur == NULL)
	{
		printf("List is empty!!\n");
		return;
	}
	while(cur)
	{
		del = cur;
		if(cur->data == x) 
		{
			//没有节点
			if(cur == *pHead)
			{
				*pHead = (*pHead)->next;
				cur = *pHead;
			}
			//一个及以上节点
			else
			{
				prev->next = cur->next;
				cur = prev->next;
			}
			free(del);
			del = NULL;
		}
		else
		{
			prev = cur;
			cur = cur->next;
		}
	}
}

void EraseNotTail(pLinkNode pos)         // 删除无头链表的非尾节点
{
	pLinkNode del = NULL;
	assert(pos);
	/*替换删除*/
	pos->data = pos->next->data;	 //将要删除节点的数据用他下一个节点的数据进行替换
	del = pos->next;
	pos->next = del->next;
	free(del);					  //删除下一个节点
	del = NULL;
}
void ReverseList(pLinkList* pHead)	  // 逆序链表
{
	pLinkNode cur = *pHead;
	pLinkNode prev = NULL; 
	pLinkNode pNewHead = NULL;
	assert(pHead);
	if(pHead == NULL)	 /*空链表*/
	{
		printf("List is empty!!\n");
		return;
	}
	else if((*pHead)->next == NULL)  /*一个节点*/
	{
		return;
	}
	else
	{
		while(cur != NULL)
		{
			prev = cur;
			cur = cur->next;
			prev->next = pNewHead;
			pNewHead = prev;
		}
		*pHead = pNewHead; // *pHead指向新的头结点
	}
}
void BubbleSort(pLinkList *pHead)			//排序链表(冒泡)
{
	pLinkNode cur = *pHead;
	pLinkNode end = NULL;
	assert(pHead);
	while(cur != end)  //冒泡的次数
	{
		while(cur && (cur->next != end))  //一次冒泡 ,最大的数放到末尾
		{
			if(cur->data > cur->next->data)	  //交换数据
			{
				DataType tmp = cur->data;
				cur->data = cur->next->data;
				cur->next->data = tmp;
			}
			cur = cur->next;
		}
		end = cur;	  //记住最大数的位置
		cur = *pHead;
	}
}
void InsertFrontNode(pLinkNode pos, DataType x)  //在当前节点前插入一个数据x
{
	pLinkNode NewNode = BuyNode(x);
	DataType tmp;
	assert(pos);
	NewNode->next = pos->next;	//替换插入	  
	pos->next = NewNode;
	tmp = pos->data;			 //交换数据
	pos->data = NewNode->data;
	NewNode->data = tmp;
}
pLinkNode Merge(pLinkList list1, pLinkList list2)	  //合并两个有序链表
{
	pLinkNode NewHead = NULL;
	pLinkNode cur = NULL;
	if(list1 == list2)	 //两个链表相等
	{
		return list1;
	}
	if((list1 == NULL) && (list2 != NULL))	
	{
		return list2;  //list1为空
	}
	if((list1 != NULL) && (list2 == NULL))
	{
		return list1;  //list2为空
	}
	/*确定头结点*/
	if(list1->data > list2->data)  
	{
		NewHead = list2;
		list2 = list2->next;
	}
	else
	{
		NewHead = list1;
		list1 = list1->next;
	}
	cur = NewHead;
	while((list1) && (list2))
	{
		if(list1->data > list2->data)
		{
			cur->next = list2;
			list2 = list2->next;
		}
		else
		{
			cur->next = list1;
			list1 = list1->next;
		}
		cur = cur->next;
	}
	/*至少一个链表此时为空,将不为空的连接在新链表的后面*/
	if(list1)
	{
		cur->next = list1;
	}
	else
	{
		cur->next = list2;
	}
	return NewHead;
	
}
pLinkNode _Merge(pLinkList list1, pLinkList list2)	//合并两个有序链表(递归)
{
	pLinkNode NewHead = NULL;
	if(list1 == list2)	 //两个链表相等
	{
		return list1;
	}
	else if((list1 == NULL) && (list2 != NULL))	
	{
		return list2;  //list1为空
	}
	else if((list1 != NULL) && (list2 == NULL))
	{
		return list1;  //list2为空
	}
	if(list1->data >list2->data)
	{
		NewHead = list2;
		NewHead->next = _Merge(list1, list2->next);	//递归调用
	}
	else
	{
		NewHead = list1;
		NewHead->next = _Merge(list1->next, list2);	  //递归调用
	}
	return NewHead;
}
pLinkNode JosephCycle(pLinkList* pHead, int num)    //约瑟夫环
{
	pLinkNode del = NULL;
	pLinkNode cur = *pHead;
	int count = 0;
	assert(pHead);
	while(1)
	{
		count = num;
		if(cur->next == cur)   //结束条件
		{
			break;
		}
		while(--count)
		{
			cur = cur->next;
		}
		printf("%d ",cur->data);
		del = cur->next;
		cur->next = del->next;
		cur->data = del->data;
		free(del);
		del = NULL;
	}
	*pHead = cur;
	printf("\n");
	return cur;
}
pLinkNode FindMidNode(pLinkList pHead)		//查找链表的中间节点
{
	pLinkNode Fast = pHead;
	pLinkNode Slow = pHead;
	assert(pHead);
	if(pHead == NULL)
	{
		printf("List is empty!!\n");
		return NULL;
	}
	while(Fast && Fast->next)
	{
		Fast = Fast->next->next;
		Slow = Slow->next;
	}
	return Slow;
}
void DelKNode(pLinkList *pHead, int k)  //删除单链表的倒数第k个节点(k > 1 && k < 链表的总长度)
{
	pLinkNode first = *pHead;
	pLinkNode second = *pHead;
	pLinkNode del =NULL;
	assert(k>1);
	//快指针先走k步
	while(--k)
	{
		//判断k是否合法(k小于链表长度)
		if(k != 0)
		{
			if(first == NULL)
			{
				printf("Please enter legal (k)!!\n");
				return;
			}
		}
		first = first->next;
	}
	//快慢指针一起走
	while(first && first->next)
	{
		first = first->next;
		second = second->next;
	}
	//替换删除
	del = second->next;
	second->data = del->data;
	second->next = del->next;
	free(del);
	del = NULL;
}
pLinkNode CheckCycle(pLinkList pList)     //判断链表是否带环
{
	pLinkNode Fast = pList;
	pLinkNode Slow = pList;
	assert(pList);
	while(Fast && Fast->next)
	{
		Fast = Fast->next->next;
		Slow = Slow->next;
		if(Fast == Slow)  //判断是否带环
		{
			return Fast;
		}
	}
	return NULL;
}
int GetCircleLength(pLinkNode meet)	 //链表带环则求环的长度和相遇节点,不带环返回-1
{
	pLinkNode cur = meet;
	int count = 0;
	do
	{
		cur = cur->next;
		count++;
	}while(cur != meet);
	return count;
}
pLinkNode GetCycleEntryNode(pLinkList list, pLinkNode meetNode) // 获取环入口点
{
	pLinkNode Entry = list;
	pLinkNode Meet = meetNode;
	while(Entry != Meet)
	{
		Entry = Entry->next;
		Meet = Meet->next;
	}
	return Entry;
}
// 【链表相交问题】
//
//判断两个链表是否相交,假设两个链表都不带环。
//
int CheckCross(pLinkList list1, pLinkList list2)
{
	pLinkNode first = list1;
	pLinkNode second = list2;
	if((first == NULL)||(second == NULL))
	{
		return -1;
	}
	while(first->next)
	{
		first = first->next;
	}
	while(second->next)
	{
		second->next;
	}
	if(first == second)
	{
		return 1;
	}
	else
	{
		return -1;
	}	
}


//测试


//test.c

#include "LinkList.h"

void test()
{
	pLinkList MyList;
	pLinkNode rec = NULL;
	int ret = 0;
	InitLinkList(&MyList);
	PushBack(&MyList,1);
	PushBack(&MyList,2);
	PushBack(&MyList,3);
	PrintList(MyList);
	PopBack(&MyList);
	PrintList(MyList);
	PushFront(&MyList, 4);
	PrintList(MyList);
	PopFront(&MyList);
	PrintList(MyList);
	ret = GetListLength(MyList);
	printf("ret = %d\n",ret);
	rec = Find(MyList, 2);
	if(rec == NULL)
		printf("表中没有此元素!!\n");
	else
		printf("rec = %d\n", rec->data);
	Insert(&MyList, rec, 6);
	PrintList(MyList);
	Erase(&MyList, rec);
	PrintList(MyList);
	Remove(&MyList, 6);
	PrintList(MyList);
	Remove(&MyList, 1);
	PrintList(MyList);
	PushBack(&MyList,1);
	PushBack(&MyList,2);
	PushBack(&MyList,1);
	PushBack(&MyList,3);
	PushBack(&MyList,1);
	PrintList(MyList);
	RemoveAll(&MyList, 1);
	PrintList(MyList);
	Destroy(&MyList);
}
//BubbleSort()
void test2()
{
	pLinkList MyList;
	pLinkNode ret = NULL;
	InitLinkList(&MyList);
	PushBack(&MyList,1);
	PushBack(&MyList,2);
	PushBack(&MyList,3);
	PrintList(MyList);
	ret = Find(MyList, 2);
	EraseNotTail(ret);
	PrintList(MyList);
	//PushBack(&MyList,3);
	PushBack(&MyList,4);
	PushBack(&MyList,5);
	PrintList(MyList);
	ReverseList(&MyList);
	PrintList(MyList);
	BubbleSort(&MyList);
	PrintList(MyList);
	Destroy(&MyList);
}
//InsertFrontNode()
void test3()
{
	pLinkList MyList;
	pLinkNode ret = NULL;
	InitLinkList(&MyList);
	PushBack(&MyList,1);
	PushBack(&MyList,2);
	PushBack(&MyList,3);
	PrintList(MyList);
	ret = Find(MyList, 2);
	printf("ret->data = %d\n",ret->data);
	InsertFrontNode(ret, 4);
	PrintList(MyList);
	Destroy(&MyList);
}
//Merge() , _Merge()
void test4()
{
	pLinkList list1;
	pLinkList list2;
	pLinkNode NewList = NULL;
	InitLinkList(&list1);
	InitLinkList(&list2);
	PushBack(&list1,1);
	PushBack(&list1,3);
	PushBack(&list1,4);
	PrintList(list1);
	PushBack(&list2,2);
	PushBack(&list2,5);
	PushBack(&list2,6);
	PrintList(list2);
	NewList = _Merge(list1,list2);
	PrintList(NewList);
	Destroy(&NewList);
}
//JosephCycle()
void test5()
{
	pLinkList MyList;
	pLinkNode ret = NULL;
	int i = 0;
	InitLinkList(&MyList);
	for(i=1; i<=41; i++)
	{
		PushBack(&MyList, i);
	}
	//创建环
	ret = Find(MyList, 41);
	ret->next = MyList;
	ret = JosephCycle(&MyList, 3);
	printf("ret = %d\n", ret->data);
	//结环,销毁空间
	ret->next = NULL;
	free(ret);
	ret = NULL;
}
//FindMidNode()
void test6()
{
	pLinkList MyList;
	pLinkNode ret = NULL;
	InitLinkList(&MyList);
	PushBack(&MyList, 1);
	PushBack(&MyList, 2);
	PushBack(&MyList, 3);
	PushBack(&MyList, 4);
	PushBack(&MyList, 5);
	PushBack(&MyList, 6);
	PrintList(MyList);
	ret = FindMidNode(MyList);
	printf("ret = %d\n", ret->data);
	Destroy(&MyList);
}
//DelKNode()
void test7()
{
	pLinkList MyList;
	pLinkNode ret = NULL;
	InitLinkList(&MyList);
	PushBack(&MyList, 1);
	PushBack(&MyList, 2);
	PushBack(&MyList, 3);
	PushBack(&MyList, 4);
	PushBack(&MyList, 5);
	PushBack(&MyList, 6);
	PrintList(MyList);
	DelKNode(&MyList, 8);
	PrintList(MyList);
	Destroy(&MyList);
}
//CheckCycle() , GetCircleLength() ,GetCycleEntryNode()
void test8()
{
	pLinkList MyList;
	pLinkNode ret1 = NULL;
	pLinkNode ret2 = NULL;
	pLinkNode ret = NULL;
	pLinkNode entry = NULL;
	int i = 0;
	InitLinkList(&MyList);
	for(i=1; i<=7; i++)
	{
		PushBack(&MyList, i);
	}
	//创建环
	ret1 = Find(MyList, 4);
	ret2 = Find(MyList, 7);
	ret2->next = ret1;
	ret = CheckCycle(MyList);
	if(ret == NULL)	 //不带环
	{
		printf("LinkList not cycle!!\n");
	}
	else			     //带环
	{
		printf("LinkList is cycle!!\n");
	}
	entry = GetCycleEntryNode(MyList, ret);
	printf("EntyrNode = %d\n", entry->data);
	printf("CircleLength = %d\n",GetCircleLength(ret));
	ret2->next = NULL;	 //解环
	Destroy(&MyList); 
}


int main()
{
	//test();
	//test2();
	//test3();
	test4();
	//test5();
	//test6();
	//test7();
	//test8();
	system("pause");
	return 0;
}


本文出自 “Pzd流川枫” 博客,请务必保留此出处http://xujiafan.blog.51cto.com/10778767/1747968

以上是关于单链表的主要内容,如果未能解决你的问题,请参考以下文章

数据结构代码(用C语言) 单链表的插入和删除

单链表

数据结构--单链表简单代码实现(总结)

单链表逆置

循环链表(循环单链表循环双链表)的相关操作的代码实现(C语言)

单链表反转java代码