【数据结构】单链表的基本操作

  本篇主要实现了单链表的增删改查,以及清空销毁单链表等基本操作。由于单链表在尾插、尾删时需要遍历整个链表,因此在下一篇中将介绍带有头结点的双向循环链表来解决这一问题。

头文件

SingleLinkList.h

# ifndef __SINGLELINKLIST_H__
# define __SINGLELINKLIST_H__

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

enum OPTION
{
	QUIT, // 退出
	ADD, // 添加
	DETELE, // 删除
	SEARCH, // 查找
	MODIFY, // 修改
	CLEAR, // 清空
	NUM_NODE, // 结点数
	IS_EMPTY, // 判空
	DESTORY, // 销毁
	SHOW // 显示
};

enum ADD_DATA
{
	EXIT_ADD, // 退出添加
	PUSH_FRONT, // 头插
	PUSH_BACK, // 尾插
	PUSH_INSERT // 任意插
};

enum DELETE_DATA
{
	EXIT_DELETE, // 退出删除
	POP_FRONT, // 头删
	POP_BACK, // 尾删
	POP_ERASE, // 任意删
	REMOVE_FIRST, // 只删除第一个要删除的
	REMOVE_ALL // 删除所有要删除的
};

typedef int DataType;

typedef struct SListNode
{
	DataType data; // 数据
	struct SListNode * pNext; // 指向下一个结点
}SListNode, * pSListNode;

void SListInit(pSListNode * pFirst); // 初始化

void SListPrint(pSListNode pFirst); // 打印链表内容

void SListPushFront(pSListNode * pFirst, DataType data); // 头插

void SListPushBack(pSListNode * pFirst, DataType data); // 尾插

void SListInsert(pSListNode * pFirst, pSListNode pPos, DataType data); // 给定结点插入,插入到结点前

void SListAdd(pSListNode * pFirst); // 单链表添加数据

void SListPopFront(pSListNode * pFirst); // 头删

void SListPopBack(pSListNode * pFirst); // 尾删

void SListErase(pSListNode * pFirst, pSListNode pPos); // 给定结点删除

void SListSearch(pSListNode pFirst); // 查找输入数据,如果找到该数据则提示找到,反之则提示没找到

void SListModify(pSListNode pFirst); // 修改单链表数据

void SListRemove(pSListNode * pFirst, DataType data); // 按值删除,只删遇到的第一个

void SListRemoveAll(pSListNode * pFirst, DataType data); // 按值删除,删除所有的

void SListDel(pSListNode * pFirst); // 单链表删除数据

void SListIsEmpty(pSListNode pFirst); // 判空

void SListSize(pSListNode pFirst); // 结点数

void SListClear(pSListNode * pFirst); // 清空

void SListDestroy(pSListNode * pFirst); // 销毁

# endif // __SINGLELINKLIST_H__

源代码

1.SingleLinkList.c

#define _CRT_SECURE_NO_WARNINGS 1

/*
* Copyright (c) 2018, code farmer from sust
* All rights reserved.
*
* 文件名称:SingleLinkList.c
* 功能:没有头结点的单链表基本操作内部实现细节
*
* 当前版本:V1.0
* 作者:sustzc
* 完成日期:2018年5月26日15:01:54
*/

# include "SingleLinkList.h"

/*
*	函数名称:SListInit
*
*	函数功能:单链表的初始化
*
*	入口参数:pFirst
*
*	出口参数:void
*
*	返回类型:void
*/

void SListInit(pSListNode * pFirst)
{
	assert(NULL != pFirst);

	*pFirst = NULL;

	return;
}

/*
*	函数名称:CreateNewNode
*
*	函数功能:创建新节点
*
*	入口参数:data
*
*	出口参数:void
*
*	返回类型:pSListNode
*/

static pSListNode CreateNewNode(DataType data)
{
	pSListNode pNewNode = (pSListNode)malloc(sizeof(SListNode));

	if (NULL == pNewNode)
	{
		perror("内存分配失败!\n");
		exit(-1);
	}
	else
	{
		pNewNode->data = data;
		pNewNode->pNext = NULL;
	}

	return pNewNode;
}

/*
*	函数名称:SListPrint
*
*	函数功能:打印链表存储的内容(ps:不需要更改链表内容,因此传一级指针即可)
*
*	入口参数:pFirst
*
*	出口参数:void
*
*	返回类型:void
*/

void SListPrint(pSListNode pFirst)
{
	pSListNode pCur = NULL;

	assert(NULL != pFirst);

	printf("链表内容为:\n");

	for (pCur = pFirst; NULL != pCur; pCur = pCur->pNext)
	{
		printf("%2d -> ", pCur->data);
	}

	printf("NULL\n");

	return;
}


/*
*	函数名称:AddMenu
*
*	函数功能:添加数据菜单显示
*
*	入口参数:void
*
*	出口参数:select
*
*	返回类型:int
*/

int AddMenu(void)
{
	int select = 0;

	printf("************************************\n");
	printf("*******        添加数据      *******\n");
	printf("*******  1. 头插    2. 尾插  *******\n");
	printf("*******  3. 任意插  0. 退出  *******\n");;
	printf("************************************\n");
	printf("select>");

	assert(1 == scanf("%d", &select));

	return select;
}

/*
*	函数名称:SListPushFront
*
*	函数功能:头插
*
*	入口参数:pFirst, data
*
*	出口参数:void
*
*	返回类型:void
*/

//void SListPushFront(pSListNode * pFirst, DataType data)
//{
//	pSListNode pNewNode = CreateNewNode(data);
//
//	assert(NULL != pFirst);
//
//	//链表为空
//	if (NULL == *pFirst)
//	{
//		*pFirst = pNewNode;
//	}
//	else
//	{
//		pNewNode->pNext = *pFirst;
//		*pFirst = pNewNode;
//	}
//
//	return;
//}

void SListPushFront(pSListNode * pFirst, DataType data)
{
	pSListNode pNewNode = CreateNewNode(data);

	assert(NULL != pFirst);

	pNewNode->pNext = *pFirst;
	*pFirst = pNewNode;

	return;
}

/*
*	函数名称:SListPushBack
*
*	函数功能:尾插
*
*	入口参数:pFirst, data
*
*	出口参数:void
*
*	返回类型:void
*/

void SListPushBack(pSListNode * pFirst, DataType data)
{
	pSListNode pNewNode = CreateNewNode(data);

	assert(NULL != pFirst);
 
	if (NULL == *pFirst) 
	{
		*pFirst = pNewNode;
	}
	else
	{
		//遍历结点
		pSListNode pCur = *pFirst;

		while (NULL != pCur->pNext)
		{
			pCur = pCur->pNext;
		}

		pNewNode->pNext = pCur->pNext;
		pCur->pNext = pNewNode;
	}
	
	return;
}

/*
*	函数名称:SListInsert
*
*	函数功能:给定结点插入,插入到结点前
*
*	入口参数:pFirst, pPos, data
*
*	出口参数:void
*
*	返回类型:void
*/

void SListInsert(pSListNode * pFirst, pSListNode pPos, DataType data)
{
	pSListNode pCur = NULL;
	pSListNode pNewNode = NULL;

	assert((NULL != pFirst) && (NULL != pPos));

	if (*pFirst == pPos)
	{
		SListPushFront(pFirst, data);
	}
	else
	{
		;
	}

	pCur = *pFirst;

	while (pPos != pCur->pNext)
	{
		pCur = pCur->pNext;
	}
	
	pNewNode = CreateNewNode(data);
	pNewNode->pNext = pPos;
	pCur->pNext = pNewNode;

	return;
}

/*
*	函数名称:SListAdd
*
*	函数功能:单链表的添加
*
*	入口参数:pFirst
*
*	出口参数:void
*
*	返回类型:void
*/

void SListAdd(pSListNode * pFirst)
{
	DataType data = 0;
	int select = AddMenu();

	assert(NULL != pFirst);

	switch (select)
	{
		case EXIT_ADD:
		{
			printf("退出添加!\n");
			break;
		}
		case PUSH_FRONT:
		{
			printf("请输入要添加的数据:>");
			assert(1 == scanf("%d", &data));

			SListPushFront(pFirst, data);
			printf("头插成功!\n");

			break;
		}
		case PUSH_BACK:
		{
			printf("请输入要添加的数据:>");
			assert(1 == scanf("%d", &data));

			SListPushBack(pFirst, data);
			printf("尾插成功!\n");

			break;
		}
		case PUSH_INSERT:
		{	
			pSListNode pCur = (*pFirst)->pNext->pNext;

			printf("请输入要添加的数据:>");
			assert(1 == scanf("%d", &data));

			SListInsert(pFirst, pCur, data);
			printf("任意插成功!\n");

			break;
		}
		default:
		{
			printf("输入有误!\n");
			break;
		}
	}

	return;
}

/*
*	函数名称:DelMenu
*
*	函数功能:删除数据菜单显示
*
*	入口参数:void
*
*	出口参数:select
*
*	返回类型:int
*/

int DelMenu(void)
{
	int select = 0;

	printf("************************************************************************\n");
	printf("*******                   删除数据                               *******\n");
	printf("*******    1. 头删                  2. 尾删                      *******\n");
	printf("*******    3. 任意删                4. 只删除要删数据中的第一个  *******\n");;
	printf("*******    5. 删除所有要删除的数据  0. 退出                      *******\n");
	printf("************************************************************************\n");
	printf("select>");

	assert(1 == scanf("%d", &select));

	return select;
}

/*
*	函数名称:SListPopFront
*
*	函数功能:头删
*
*	入口参数:pFirst
*
*	出口参数:void
*
*	返回类型:void
*/

void SListPopFront(pSListNode * pFirst)
{
	pSListNode pCur = NULL;
	pSListNode pNextNode = NULL;

	if (NULL == *pFirst)
	{
		printf("链表为空!\n");
	}
	else
	{
		pCur = *pFirst;
		pNextNode = pCur->pNext;

		free(pCur);
		*pFirst = pNextNode;
	}

	return;
}

/*
*	函数名称:SListPopBack
*
*	函数功能:尾删
*
*	入口参数:pFirst
*
*	出口参数:void
*
*	返回类型:void
*/

void SListPopBack(pSListNode * pFirst)
{
	pSListNode pCur = NULL;
	pSListNode pNextNode = NULL;

	if (NULL == *pFirst)
	{
		printf("链表为空!\n");
	}
	else if (NULL == (*pFirst)->pNext)
		{
			free(*pFirst);
			*pFirst = NULL;
		}
		else
		{
			pCur = *pFirst;

			while (NULL != pCur->pNext->pNext)
			{
				pCur = pCur->pNext;
			}

			pNextNode = pCur->pNext;
			pCur->pNext = pNextNode->pNext;
			free(pNextNode);
		}
	
	return;
}

/*
*	函数名称:SListPopBack
*
*	函数功能:给定结点删除
*
*	入口参数:pFirst, pPos
*
*	出口参数:void
*
*	返回类型:void
*/

void SListErase(pSListNode * pFirst, pSListNode pPos)
{
	pSListNode pCur = NULL;

	if (NULL == *pFirst)
	{
		printf("链表为空!\n");
	}
	else if (NULL == pPos)
		{
			printf("删除的结点不存在!\n");
		}
		else if (pPos == *pFirst)
			{
				SListPopFront(pFirst);
			}
			else
			{
				pCur = *pFirst;

				while (pPos != pCur->pNext)
				{
					pCur = pCur->pNext;
				}

				pCur->pNext = pPos->pNext;
				free(pPos);
			}

	return;
}

/*
*	函数名称:SListFind
*
*	函数功能:按值查找,返回第一个找到的结点指针,如果没找到,返回 NULL
*
*	入口参数:pFirst, data
*
*	出口参数:pCur or NULL
*
*	返回类型:pSListNode
*/

static pSListNode SListFind(pSListNode pFirst, DataType data)
{
	pSListNode pCur = NULL;

	assert(NULL != pFirst);

	for (pCur = pFirst; NULL != pCur; pCur = pCur->pNext)
	{
		if (data == pCur->data)
		{
			return pCur;
		}
		else
		{
			;
		}
	}

	return NULL;
}

/*
*	函数名称:SListSearch
*
*	函数功能:查找输入数据,如果找到该数据则提示找到,反之则提示没找到 
*
*	入口参数:pFirst
*
*	出口参数:void
*
*	返回类型:void
*/

void SListSearch(pSListNode pFirst)
{
	DataType data = 0;
	pSListNode pPosNode = NULL;

	assert(NULL != pFirst);

	printf("请输入要查找的数据:>");
	assert(1 == scanf("%d", &data));
	pPosNode = SListFind(pFirst, data);

	if (NULL != pPosNode)
	{
		printf("找到了%d\n", data);
	}
	else
	{
		printf("没找到%d\n", data);
	}

	return;
}

/*
*	函数名称:SListModify
*
*	函数功能:修改单链表数据 
*
*	入口参数:pFirst
*
*	出口参数:void
*
*	返回类型:void
*/

void SListModify(pSListNode pFirst)
{
	pSListNode pPosNode = NULL;
	DataType old_data = 0;
	DataType new_data = 0;

	assert(NULL != pFirst);

	printf("请输入要修改的数据:>");
	assert(1 == scanf("%d", &old_data));

	pPosNode = SListFind(pFirst, old_data);

	if (NULL != pPosNode)
	{
		printf("请输入修改后的数据:>");
		assert(1 == scanf("%d", &new_data));

		pPosNode->data = new_data;

		printf("修改成功!\n");
	}
	else
	{
		printf("没找到%d\n", old_data);
	}

	return;
}

/*
*	函数名称:SListRemove
*
*	函数功能:按值删除,只删遇到的第一个
*
*	入口参数:pFirst, data
*
*	出口参数:void
*
*	返回类型:void
*/

void SListRemove(pSListNode * pFirst, DataType data)
{
	pSListNode pPosNode = SListFind(*pFirst, data);

	if (NULL != pPosNode)
	{
		SListErase(pFirst, pPosNode);
	}
	else
	{
		printf("要删除的数据不存在!\n");
	}

	return;
}

/*
*	函数名称:SListRemoveAll
*
*	函数功能:按值删除,删除所有的
*
*	入口参数:pFirst, data
*
*	出口参数:void
*
*	返回类型:void
*/

void SListRemoveAll(pSListNode * pFirst, DataType data)
{
	pSListNode pCur = *pFirst;
	pSListNode pNextNode = NULL;

	if (data == (*pFirst)->data)
	{
		SListPopFront(pFirst);
	}
	else
	{
		while (NULL != pCur->pNext)
		{
			if (data == pCur->pNext->data)
			{
				pNextNode = pCur->pNext;
				pCur->pNext = pNextNode->pNext;
				free(pNextNode);
			}
			else
			{
				pCur = pCur->pNext;
			}
		}
	}

	return;
}

/*
*	函数名称:SListDel
*
*	函数功能:单链表的删除
*
*	入口参数:pFirst
*
*	出口参数:void
*
*	返回类型:void
*/

void SListDel(pSListNode * pFirst)
{
	DataType data = 0;
	int select = DelMenu();

	assert(NULL != pFirst);

	switch (select)
	{
		case EXIT_DELETE:
		{
			printf("退出删除!\n");
			break;
		}
		case POP_FRONT:
		{
			SListPopFront(pFirst);
			printf("头删成功!\n");

			break;
		}
		case POP_BACK:
		{
			SListPopBack(pFirst);
			printf("尾删成功!\n");

			break;
		}
		case POP_ERASE:
		{
			SListErase(pFirst, (*pFirst)->pNext->pNext);
			printf("任意删成功!\n");

			break;
		}
		case REMOVE_FIRST:
		{
			printf("请输入要删除的数据:>");
			assert(1 == scanf("%d", &data));

			SListRemove(pFirst, data);
			printf("删除第一个要删除的数据成功!\n");

			break;
		}
		case REMOVE_ALL:
		{
			printf("请输入要删除的数据:>");
			assert(1 == scanf("%d", &data));

			SListRemoveAll(pFirst, data);
			printf("要删除的数据删除成功!\n");

			break;
		}
		default:
		{
			printf("输入有误!\n");
			break;
		}
	}

	return;
}

/*
*	函数名称:SListIsEmpty
*
*	函数功能:单链表是否为空
*
*	入口参数:pFirst
*
*	出口参数:void
*
*	返回类型:void
*/

void SListIsEmpty(pSListNode pFirst)
{
	pSListNode pCur = NULL;

	assert(NULL != pFirst);

	pCur = pFirst->pNext;

	if (NULL != pCur)
	{
		printf("链表不为空!\n");
	}
	else
	{
		printf("链表为空!\n");
	}

	return;
}

/*
*	函数名称:SListSize
*
*	函数功能:单链表的结点数(ps:不需要更改链表内容,因此传一级指针即可)
*
*	入口参数:pFirst
*
*	出口参数:void
*
*	返回类型:void
*/

void SListSize(pSListNode pFirst)
{
	int count = 0;
	pSListNode pCur = NULL;

	assert(NULL != pFirst);

	for (pCur = pFirst; NULL != pCur; pCur = pCur->pNext)
	{
		count++;
	}

	printf("单链表的结点数为: %d\n", count);
		
	return ;
}

/*
*	函数名称:SListClear
*
*	函数功能:清空单链表
*
*	入口参数:pFirst
*
*	出口参数:void
*
*	返回类型:void
*/

void SListClear(pSListNode * pFirst)
{
	pSListNode pNode = NULL;
	pSListNode pNextNode = NULL;

	assert(NULL != pFirst);

	for (pNode = *pFirst; NULL != pNode->pNext; pNode = pNextNode) 
	{
		pNextNode = pNode->pNext;
		free(pNode);
	}
	
	(*pFirst)->pNext = NULL;

	printf("清空单链表成功!\n");

	return;
}

/*
*	函数名称:SListDestroy
*
*	函数功能:销毁单链表
*
*	入口参数:pFirst
*
*	出口参数:void
*
*	返回类型:void
*/

void SListDestroy(pSListNode * pFirst)
{
	pSListNode pNode = NULL;
	pSListNode pNextNode = NULL;

	assert(NULL != pFirst);

	for (pNode = *pFirst; NULL != pNode; pNode = pNextNode) 
	{
		pNextNode = pNode->pNext;
		free(pNode);
	}

	*pFirst = NULL;

	printf("销毁单链表成功!\n");

	return;
}

2.test.c

#define _CRT_SECURE_NO_WARNINGS 1

/*
* Copyright (c) 2018, code farmer from sust
* All rights reserved.
*
* 文件名称:test.c
* 功能:测试单链表基本操作
*
* 当前版本:V1.0
* 作者:sustzc
* 完成日期:2018年5月26日15:00:40
*/

# include "SingleLinkList.h"

/*
*	函数名称:MainMenu
*
*	函数功能:单链表主菜单显示
*
*	入口参数:void
*
*	出口参数:choose
*
*	返回类型:int
*/

int MainMenu(void)
{
	int choose = 0;

	printf("**************************************\n");
	printf("*******      欢迎操作单链表     *******\n");
	printf("*******  1. 添加      2. 删除  *******\n");
	printf("*******  3. 查找      4. 修改  *******\n");
	printf("*******  5. 清空      6. 数量  *******\n");
	printf("*******  7. 判空      8. 销毁  *******\n");
	printf("*******  9. 显示      0. 退出  *******\n");
	printf("**************************************\n");
	printf("choose>");

	assert(1 == scanf("%d", &choose));

	return choose;
}

/*
*	函数名称:main
*
*	函数功能:主程序
*
*	入口参数:void
*
*	出口参数:0
*
*	返回类型:int
*/

int main(void)
{
	int choose = 0;
	pSListNode slnode = NULL;
	//初始化单链表
	SListInit(&slnode);

	do
	{
		choose = MainMenu();

        switch(choose)
		{
			case QUIT:
				printf("退出单链表!\n");
				break;
			case ADD:
				{
					SListAdd(&slnode);
					SListAdd(&slnode);
					SListAdd(&slnode);	
				}
				break;
			case DETELE:
				SListDel(&slnode);
				break;
			case SEARCH:
				SListSearch(slnode);
				break;
			case MODIFY:
				SListModify(slnode);
				break;
			case CLEAR:
				SListClear(&slnode);
				break;
			case NUM_NODE:
				SListSize(slnode);
				break;
			case IS_EMPTY:
				SListIsEmpty(slnode);
				break;
			case DESTORY:
				SListDestroy(&slnode);
				break;
			case SHOW:
				SListPrint(slnode);
				break;
			default:
				printf("输入有误,请重新输入!\n");
				break;
		}
	}while(choose);

	return 0;
}

输出结果

首先,插入6个数据(ps:插入方式为头插、尾插、任意插),


接着对链表进行判空,


然后计算链表的结点数,


修改链表的数据,


修改后的内容是:


删除所有的4,



删除第一个5,



头删后,


尾删后,


最后销毁单链表。


猜你喜欢

转载自blog.csdn.net/sustzc/article/details/80551501