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