数据结构--链表的基本功能实现

链表实现下面功能
//初始化链表
void InitLinkList(pList* pplist);
//销毁链表
void DestroyLinkList(pList* pplist);
//销毁节点
void Destroy(pList* pplist);
//打印
void PrintList(pList plist);
//尾插
void PushBack(pList* pplist, DataType d);
//尾删
void PopBack(pList* pplist);
//头插
void PushFront(pList* pplist, DataType d);
//头删
void PopFront(pList* pplist);
//查找
pNode Find(pList plist, DataType d);
//指定位置插入
void Insert(pList* pplist, pNode pos, DataType d);
//指定位置删除
void Erase(pList* pplist, pNode pos);
//删除指定元素
void Remove(pList* pplist, DataType d);
//删除所有指定元素
void RemoveAll(pList* pplist, DataType d);
//删除无头单链表的非尾节点(不能遍历链表)
void EraseNotTailNode(pNode pos);
//链表长度
int GetListLength(pList plist);
//递归方法从尾到头打印
void PrintTailToHeadRec(pList plist);
//非递归从尾到头打印
void PrintTailToHead(pList plist);
//在无头单链表的一个节点前插入一个节点(不能遍历链表)
void InsertNotTailNode(pNode pos, int num);
//单链表实现约瑟夫环
pNode JosephCircle(pList* pplist, int num);
//逆置反转单链表
void TailToHeadListWayOne(pList* pplist);
void TailToHeadListWayTwo(pList* pplist);

Linklist.h  头文件

#ifndef __LINKLIST_H__
#define __LINKLIST_H__

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

//定义元素类型
typedef int DataType;	

//链表的定义
typedef struct Node
{
	DataType data;			//存放数据
	struct Node* next;		//定义一个struct Node类型的指针记录下一个节点的地址
}Node,*pNode,List,*pList;

//初始化链表
void InitLinkList(pList* pplist);
//销毁链表
void DestroyLinkList(pList* pplist);
//销毁节点
void Destroy(pList* pplist);
//打印
void PrintList(pList plist);
//尾插
void PushBack(pList* pplist, DataType d);
//尾删
void PopBack(pList* pplist);
//头插
void PushFront(pList* pplist, DataType d);
//头删
void PopFront(pList* pplist);
//查找
pNode Find(pList plist, DataType d);
//指定位置插入
void Insert(pList* pplist, pNode pos, DataType d);
//指定位置删除
void Erase(pList* pplist, pNode pos);
//删除指定元素
void Remove(pList* pplist, DataType d);
//删除所有指定元素
void RemoveAll(pList* pplist, DataType d);
//删除无头单链表的非尾节点(不能遍历链表)
void EraseNotTailNode(pNode pos);
//链表长度
int GetListLength(pList plist);
//递归方法从尾到头打印
void PrintTailToHeadRec(pList plist);
//非递归从尾到头打印
void PrintTailToHead(pList plist);
//在无头单链表的一个节点前插入一个节点(不能遍历链表)
void InsertNotTailNode(pNode pos, int num);
//单链表实现约瑟夫环
pNode JosephCircle(pList* pplist, int num);
//逆置反转单链表
void TailToHeadListWayOne(pList* pplist);
void TailToHeadListWayTwo(pList* pplist);

#endif __LINKLIST_H__

Linllist.c 文件

#include "Linklist.h"

//链表的初始化
void InitLinkList(pList* pplist)
{
	*pplist = NULL;
}
//申请节点
pNode BuyNode(DataType d)
{
	pNode L = (Node *)malloc(sizeof(Node));
	if (L == NULL)
	{
		perror("Buy Node");
		exit(FILENAME_MAX);
	}
	L->data = d;
	L->next = NULL;
	return L;
}
//销毁节点
void Destroy(pList* pplist)
{
	pNode del = NULL;
	assert(pplist);
	del = *pplist;
	*pplist = (*pplist)->next;
	free(del);
	del = NULL;
}
//销毁链表
void DestroyLinkList(pList*  pplist)
{
	pNode del = NULL;
	assert(pplist);
	while (*pplist)
	{
		del = *pplist;
		*pplist = (*pplist)->next;
		free(del);
		del = NULL;
	}
}
//尾插
void PushBack(pList* pplist, DataType d)
{
	pNode p;
	assert(pplist);
	p = *pplist;
	//当链表为空,不需要遍历链表,需特殊处理
	if (p == NULL)
	{
		*(pplist) = BuyNode(d);
	}
	else
	{
		//遍历链表,找到尾节点
		while (p->next != NULL)
		{
			p = p->next;
		}
		p->next = BuyNode(d);
	}
}
//尾删
void PopBack(pList* pplist)
{
	pNode ret = NULL;
	pNode del = *pplist;
	assert(pplist);
	assert(*pplist);
	//当链表只有一个非空节点时,直接删除
	if (del->next == NULL)
	{
		Destroy(&del);
		*pplist = NULL;
		return;
	}
	//遍历链表,找到尾节点
	while (del->next != NULL)
	{
		ret = del;
		del = del->next;
	}
	ret->next = NULL;
	Destroy(&del);
}
//头插
void PushFront(pList* pplist, DataType d)
{
	pNode newNode;
	assert(pplist);
	newNode = BuyNode(d);
	newNode->next = *pplist;
	*pplist = newNode;
}
//头删
void PopFront(pList* pplist)
{
	pNode del = NULL;
	assert(pplist);
	assert(*pplist);  //链表非空
	del = *pplist;
	*pplist = del->next;
	Destroy(&del);
}
//查找
pNode Find(pList plist, DataType d)
{
	assert(plist);
	while (plist)
	{
		if (plist->data == d)
		{
			return plist;
		}
		plist = plist->next;
	}
	return NULL;
}
//指定位置插入
void Insert(pList* pplist, pNode pos, DataType d)
{
	pNode newNode = NULL;
	pNode ret = NULL;
	assert(pplist);
	ret = *pplist;
	newNode = BuyNode(d);
	//当插入位置为头结点时,则头插
	if (pos == *pplist)
	{
		newNode->next = *pplist;
		*pplist = newNode;
		return;
	}
	//查找pos的上一个节点
	while (ret && (ret->next != pos))
	{
		ret = ret->next;
	}
	//找不到直接返回
	if (ret == NULL)
	{
		return;
	}
	//插入
	else
	{
		newNode->next = pos;
		ret->next = newNode;
	}
}
//指定位置删除
void Erase(pList* pplist, pNode pos)
{
	pNode ret = *pplist;
	pNode del = *pplist;
	assert(pplist);
	assert(pos);
	assert(*pplist);
	if (pos == *pplist)
	{
		*pplist = (*pplist)->next;
		Destroy(&del);
		return;
	}
	//ret记录被删除节点的上一个节点位置
	while (del != pos)
	{
		ret = del;
		del = del->next;
	}
	ret->next = del->next;
	Destroy(&del);
}
//删除指定元素
void Remove(pList* pplist, DataType d)
{
	pNode ret = NULL;
	pNode del = NULL;
	pNode newNode = NULL;
	assert(pplist);
	assert(*pplist);
	ret = *pplist;
	del = *pplist;
	//调用查找函数,查找要删除元素的节点地址
	newNode = Find(*pplist, d);
	if (newNode == NULL)
	{
		printf("删除元素不存在!\n");
		return;
	}
	else
	{
		//头删
		if (ret == newNode)
		{
			del = *pplist;
			*pplist = (*pplist)->next;
			Destroy(&del);
			return;
		}
		while (ret->next != newNode)
		{
			ret = ret->next;
		}
		    del = ret->next;
			ret->next = del->next;
			Destroy(&del);
	}
}
//删除所有指定元素
void RemoveAll(pList* pplist, DataType d)
{
	pNode ret = NULL;
	pNode del = NULL;
	pNode newNode = NULL;
	assert(pplist);
	assert(*pplist);
	ret = *pplist;
	del = *pplist;
	while (ret)
	{
		newNode = Find(*pplist, d);
		if (newNode == NULL)
		{
			return;
		}
		else
		{
			if (ret == newNode)
			{
				del = *pplist;
				*pplist = (*pplist)->next;
				Destroy(&del);
				ret = *pplist;  //更新ret
			}
			else
			{
				while (ret->next != newNode)
				{
					ret = ret->next;
				}
				del = ret->next;
				ret->next = del->next;
				Destroy(&del);
			}
		}
	}
}
//删除无头单链表的非尾节点(不能遍历链表
//思想:相当与将被删节点的下一个节点的数据存放在被删节点中,然后删除被删节点的下一个节点即可
void EraseNotTailNode(pNode pos)
{
	pNode del = NULL;
	assert(pos);
	if (pos->next == NULL)
	{
		return;
	}	
	del = pos->next;
	pos->data = del->data;
	pos->next = del->next;
	Destroy(&del);
}
//链表长度
int GetListLength(pList plist)
{
	int count = 0;
	if (plist == NULL)
	{
		return 0;
	}
	else
	{
		while (plist)
		{
			count++;
			plist = plist->next;
		}
		return count;
	}
}
//递归方法从尾到头打印
void PrintTailToHeadRec(pList plist)
{
	if (plist == NULL)
	{
		return;
	}
	else
	{
		PrintTailToHead(plist->next);
	}
	printf("%d->", plist->data);
}
//非递归方法从尾到头打印
void PrintTailToHead(pList plist)
{
	pNode tail = NULL;
	pNode cur = NULL;
	assert(plist);
	while (plist != tail)
	{
		cur = plist;
		while (cur->next != tail)
		{
			cur = cur->next;
		}
		//不断更新tail,直到tail == plist
		tail = cur;
		printf("%d->", tail->data);
	}
}
//在无头单链表的一个节点前插入一个节点(不能遍历链表)
//思想:将要插入节点的数据和pos进行交换,然后插入pos后面即可
void InsertNotTailNode(pNode pos, DataType d)
{
	pNode newNode = BuyNode(pos->data);
	assert(pos);
	pos->data = d;
	newNode->next = pos->next;
	pos->next = newNode;
}
约瑟夫环:约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列
举例:约瑟夫环(约瑟夫问题)是一个非常经典的数学的应用问题:简化来说就是已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。开始从编号为k的人报数,数到数字为m的那个人出列;继续,他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列!

关于约瑟夫: Josephus有过的故事:39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓。于是决定了自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀。然后下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。


//单链表实现约瑟夫环
pNode JosephCircle(pList* pplist, int count)
{
	//pre记录被删节点的上一个节点
	pNode pre = NULL;
	//cur记录被删节点
	pNode cur = NULL;
	int ret = 0;
	assert(pplist);
    cur = *pplist;
	while ((*pplist)->next != *pplist)
	{	
		ret = count;
		while (--ret)
		{
			pre = cur;
			cur = cur->next;
		}
		pre->next = cur->next;
		Destroy(&cur);
		cur = pre->next;
	}
	return cur;
}

逆置翻转单链表:

方法一:用三个指针分别为first,second,third分别记录要插入的位置,要插入的节点,要插入节点的下一个节点,用头插将2插在1的前面,然改变first,second,third,继续重复上述操作,直到second指向NULL时结束,再将*pplist = first,逆置结束。

图解:


代码:

//逆置反转单链表
void TailToHeadListWayOne(pList* pplist)
{
	pNode first = NULL;
	pNode second = NULL;
	pNode third = NULL;
	assert(pplist);
	assert(*pplist);
	if ((*pplist)->next == NULL)
	{
		return;
	}
	first = *pplist;
	second = first->next;
	third = second->next;
	while (second)
	{
		if (first == *pplist)
		{
			first->next = NULL;
		}
		second->next = first;
		first = second;
		second = third;
		if (third != NULL)
		{
			third = third->next;
		}
	}
	*pplist = first;
}
方法二:创建一个空指针head,再用一个cur指针指向*pplist,tmp指针指向cur->next;先将cur指向head,然后更新head = cur,cur = tmp,tmp = tmp->next,直到cur为空时循环结束*pplist = head;
代码:

void TailToHeadListWayTwo(pList* pplist)
{
	pNode head = NULL;
	pNode cur = NULL;
	pNode tmp = NULL;
	assert(pplist);
	assert(*pplist);
	if ((*pplist)->next == NULL)
	{
		return;
	}
	cur = *pplist;
	tmp = cur->next;
	while (cur)
	{
		cur->next = head;
		head = cur;
		cur = tmp;
		if (tmp != NULL)
		{
			tmp = tmp->next;
		}
	}
	*pplist = head;
}
test.c 测试文件

#include "Linklist.h"

void testPushBack()
{
	pList plist;
	InitLinkList(&plist);
	PushBack(&plist, 1);
	PushBack(&plist, 2);
	PushBack(&plist, 3);
	PushBack(&plist, 4);
	PopBack(&plist);
	PopBack(&plist);
	PopBack(&plist);
	PopBack(&plist);
	PrintList(plist);
	DestroyLinkList(&plist);
}
void testPushfront()
{
	pList plist;
	InitLinkList(&plist);
	PushFront(&plist, 1);
	PushFront(&plist, 2);
	PushFront(&plist, 3);
	PushFront(&plist, 4);
	PopFront(&plist);
	PopFront(&plist);
	PopFront(&plist);
	PopFront(&plist);
	PrintList(plist);
	DestroyLinkList(&plist);
}
void testInsert()
{
	pNode pos = NULL;
	pList plist;
	InitLinkList(&plist);
	PushBack(&plist, 1);
	PushBack(&plist, 2);
	PushBack(&plist, 3);
	PushBack(&plist, 4);
	pos = Find(plist, 4);
	if (pos != NULL)
	{
		Insert(&plist, pos, 5);
	}
	PrintList(plist);
	DestroyLinkList(&plist);
}
void testErase()
{
	pNode pos = NULL;
	pList plist;
	InitLinkList(&plist);
	PushBack(&plist, 1);
	PushBack(&plist, 2);
	PushBack(&plist, 3);
	PushBack(&plist, 4);
	pos = Find(plist, 2);
	if (pos != NULL)
	{
		Erase(&plist, pos);
	}
	PrintList(plist);
	DestroyLinkList(&plist);
}
void testRemove()
{
	int length = 0;
	pList plist;
	InitLinkList(&plist);
	PushBack(&plist, 2);
	PushBack(&plist, 2);
	PushBack(&plist, 3);
	PushBack(&plist, 4);
	PushBack(&plist, 2);
	RemoveAll(&plist, 2);
	length = GetListLength(plist);
	printf("单链表长度为:%d\n", length);
	PrintList(plist);
	DestroyLinkList(&plist);
}
void testEraseNotTailNode()
{
	pList plist;
	pNode newNode = NULL;
	InitLinkList(&plist);
	PushBack(&plist, 1);
	PushBack(&plist, 2);
	PushBack(&plist, 3);
	PushBack(&plist, 4);
	PushBack(&plist, 5);
	newNode = Find(plist, 3);
	EraseNotTailNode(newNode);
	PrintList(plist);
	DestroyLinkList(&plist);
}
void testPrintTailToHeadRec()
{
	pList plist;
	InitLinkList(&plist);
	PushBack(&plist, 1);
	PushBack(&plist, 2);
	PushBack(&plist, 3);
	PushBack(&plist, 4);
	PushBack(&plist, 5);
	PrintTailToHeadRec(plist);
}
void testPrintTailToHead()
{
	pList plist;
	InitLinkList(&plist);
	PushBack(&plist, 1);
	PushBack(&plist, 2);
	PushBack(&plist, 3);
	PushBack(&plist, 4);
	PushBack(&plist, 5);
	PrintTailToHead(plist);
}
void testInsertNotTailNode()
{
	pList plist;
	pNode newNode = NULL;
	InitLinkList(&plist);
	PushBack(&plist, 1);
	PushBack(&plist, 2);
	PushBack(&plist, 3);
	PushBack(&plist, 4);
	PushBack(&plist, 5);
	newNode = Find(plist, 3);
	InsertNotTailNode(newNode, 6);
	PrintList(plist);
	DestroyLinkList(&plist);
}
void testJosephCircle()
{
	pList plist;
	pNode head = NULL;
	pNode tail = NULL;
	pNode newNode = NULL;
	InitLinkList(&plist);
	PushBack(&plist, 1);
	PushBack(&plist, 2);
	PushBack(&plist, 3);
	PushBack(&plist, 4);
	head = plist;
	tail = plist;
	while (tail->next && tail)
	{
		tail = tail->next;
	}
	//head = pHead(plist);
	//tail = pTail(plist);
	tail->next = head;
	newNode = JosephCircle(&plist, 3);
	printf("剩余的数字为:%d\n", newNode->data);
	free(plist);
	plist = NULL;
}
void testTailToHeadListWayOne()
{
	pList plist;
	InitLinkList(&plist);
	PushBack(&plist, 1);
	PushBack(&plist, 2);
	PushBack(&plist, 3);
	PushBack(&plist, 4);
	PushBack(&plist, 5);
	TailToHeadListWayOne(&plist);
	PrintList(plist);
	DestroyLinkList(&plist);
}
void testTailToHeadListWayTwo()
{
	pList plist;
	InitLinkList(&plist);
	PushBack(&plist, 1);
	PushBack(&plist, 2);
	PushBack(&plist, 3);
	PushBack(&plist, 4);
	PushBack(&plist, 5);
	TailToHeadListWayTwo(&plist);
	PrintList(plist);
	DestroyLinkList(&plist);
}
int main()
{
//     testPushBack();
//     testPushfront();
//     testInsert();
//     testErase();
//     testRemove();
//     testEraseNotTailNode();
//     testPrintTailToHead();
//     testPrintTailToHead();
//     testInsertNotTailNode();
//     testJosephCircle();
//     testTailToHeadListWayOne();
//     testTailToHeadListWayTwo();
       system("pause");
    return 0;
}










猜你喜欢

转载自blog.csdn.net/ds19980228/article/details/80863806