目录
3.6 查找数据函数:给一个数据,返回这个数据所在节点的地址的函数
3.7 随即删除节点:给数据返回其所在节点地址,删除这个节点的函数
3.8 修改数据函数:给一个数据,找到这个数据所在的节点,并用新数据修改
一、单链表的处理
1、节点的设置
typedef int SLdatetype;//重定义类型名,这样可以修改想要的类型
typedef struct SListNode SLNode;//重定义结构体类型的名字
struct SListNode //单链表节点
{
SLdatetype date;
SLNode* next;
};
2、节点(结构体)内存空间的开辟
SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
newnode->date = x;//将需要的数据x放入节点里
newnode->next = NULL;//创建一个新的节点
二、单链表功能的实现
1、整体框架
int main()
{
menu();
int input = 0;
do
{
fprintf(stdout, "请输入:>");
fscanf(stdin,"%d",
switch (input)
{
case 1:
testSList1();//进入尾插数据操作
fprintf(stdout, "尾插数据成功\n");
break;
case 2:
testSList2();//进入头插数据操作
fprintf(stdout, "头插数据成功\n");
break;
case 3:
testSList3();//进入头删数据操作
fprintf(stdout, "头删数据成功\n");
break;
case 4:
testSList4();//进入尾删数据操作
fprintf(stdout, "尾删数据成功\n");
break;
case 5:
testSList5();//进入随机插入数据操作
fprintf(stdout, "随机插入数据成功\n");
break;
//testSList6();
case 6:
testSList7();//进入随机删除数据操作
fprintf(stdout, "随机删除数据成功\n");
break;
case 7:
testSList8();//进入修改数据操作
break;
case 0:
printf("退出\n");
break;
default:
fprintf(stdout, "选择错误,请重新选择\n");
}
} while (input);
}
2、主菜单
void menu()
{
printf("*************************************\n");
printf("***** 1、尾插 2、头插 *****\n");
printf("***** 3、头删 4、尾删 *****\n");
printf("***** 5、随机插 6、随机删 *****\n");
printf("***** 7、修改 0、退出 *****\n");
printf("*************************************\n");
}
3、功能的实现
3.1 打印单链表数据功能的实现
//打印单链表
void SListPrint(SLNode* phead)//实参是单链表的第一个节点的地址
{
while (phead != NULL)
{
printf("%d->", phead->date);
phead = phead->next;
}
printf("NULL\n");
}
3.2 从单链表尾部插入节点功能的实现
//尾插函数
void SListPushBack(SLNode** pphead, SLdatetype x)
{
SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
newnode->date = x;
newnode->next = NULL;//创建一个新的节点
if (*pphead == NULL)//当没有节点的时候,这时候开辟的内存就给plist
{
*pphead = newnode;
}
else
{
SLNode* cru = *pphead;
while (cru->next != NULL)//这里必须改变节点里面的指针next存放的地址
{
cru = cru->next;
}
cru->next = newnode;//所以这里必须用cru->next访问这个指针才可以改变next存放的地址
}
}
3.3 从单链表头部插入节点功能的实现
//头插函数
void SListPushFront(SLNode** pphead, SLdatetype x)
{
SLNode* newcode = (SLNode*)malloc(sizeof(SLNode));
newcode->date = x;
newcode->next = NULL;
//if (*pphead == NULL)//当单链表里没有节点的时候
//{
// *pphead = newcode;
//}
//else
//{
newcode->next = *pphead;//这里已经包括了单链表没有节点的时候,所以可以不用上面if
*pphead = newcode;
//}
}
3.4 从单链表头部删除节点功能的实现
//头删函数 因为节点是动态开辟的,所以直接用free函数就能删除,
//一般来说释放空间后,指向这块空间的指针要置为空指针
void SListPopFront(SLNode** pphead)
{
if (*pphead != NULL)//如果空指针,即没有节点,那么就不需要删除
{
SLNode* next0 = (*pphead)->next;//这里也满足只有一个节点的情况
free(*pphead);
*pphead = next0;
}
}
3.5 从单链表尾部删除节点功能的实现
//尾删函数 因为同样节点是动态开辟的,所以直接用free函数释放空间
void SListPopBack(SLNode** pphead)
{
if (*pphead)//如果单链表没有节点,即plist是空指针,就不进入尾删
{
SLNode* cru = *pphead;
SLNode* prev = NULL;
if((*pphead)->next==NULL)
{
free(*pphead);
*pphead = NULL;
}
while (cru->next != NULL)//新定义一个指针,得到尾删节点的前一个节点的地址
{
prev = cru;
cru = cru->next;
}
prev->next = NULL;
free(cru);
cru = NULL;
}
}
3.6 查找数据函数:给一个数据,返回这个数据所在节点的地址的函数
//给一个数据,返回这个数据所在节点的地址的函数
SLNode* SListFindDate(SLNode* phead, SLdatetype x)
//因为不需要改变指向第一个节点的指针的值,
//即不需要改变这个指针存放的地址
{
while (phead != NULL)//如果没有节点,根本不会进入循环去找
{
if (phead->date == x)
{
return phead;
}
else
{
phead = phead->next;
}
}
return NULL;
}
3.7 随即插入节点:在返回的节点地址前插入一个节点的函数
//在返回的节点地址pos前插入一个数据的函数
void SListPushpos(SLNode** pphead,SLdatetype x,SLdatetype y)
{
SLNode* prev = NULL;
SLNode* cru = *pphead;
SLNode* pos = SListFindDate(*pphead, x);
SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
newnode->date = y;
newnode->next = NULL;
if (pos != NULL)//如果是没找到这个数据,或者没有节点,就不随机插
{
while (cru != pos)
{
prev = cru;
cru = cru->next;
}
if (prev != NULL)
{
newnode->next = pos;
prev->next = newnode;
}
else
{
newnode->next = pos;
*pphead = newnode;
}
}
}
3.7 随即删除节点:给数据返回其所在节点地址,删除这个节点的函数
//给数据返回其所在节点地址,删除这个节点的函数
void SListPopdate(SLNode** pphead, SLdatetype x)
{
SLNode* cru = *pphead;
SLNode* prev = NULL;
SLNode* pos = SListFindDate(*pphead, x);
if (pos != NULL)//如果是没找到这个数据,或者没有节点,就不随机删
{
while (cru != pos)
{
prev = cru;
cru = cru->next;
}
if (prev != NULL)
{
prev->next = pos->next;
free(pos);
pos = NULL;
}
else
{
*pphead = pos->next;
free(cru);
cru = NULL;
}
}
}
3.8 修改数据函数:给一个数据,找到这个数据所在的节点,并用新数据修改
//给一个数据,找到这个数据所在的节点,并用新数据修改
void SListChangeDate(SLNode* phead, SLdatetype x,SLdatetype y)
//因为不需要改变节点的地址,所以值传递即可
//x是查找的数据,y是新数据,用来修改查找的数据
{
SLNode* cru = phead;
while (cru != NULL)//如果没有节点,根本不会进入循环去找
{
if (cru->date == x)
{
cru->date = y;
break;//修改完数据后,就跳出循环
}
else
{
cru = cru->next;
}
}
if (cru == NULL)//如果循环完单链表,没有找到要修改的那个数据
{
fprintf(stdout, "要修改的数据不存在,请重新修改数据\n");
}
else
{
fprintf(stdout, "修改成功\n");
}
}
三、总代码
1、源函数代码test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"
//主菜单
void menu()
{
printf("*************************************\n");
printf("***** 1、尾插 2、头插 *****\n");
printf("***** 3、头删 4、尾删 *****\n");
printf("***** 5、随机插 6、随机删 *****\n");
printf("***** 7、修改 0、退出 *****\n");
printf("*************************************\n");
}
//验证尾插函数
void testSList1()
{
SLNode* plist = NULL;//指针一定要初始化,不然会变成野指针
SListPushBack(
SListPushBack(
SListPushBack(
SListPushBack(
SListPrint(plist);
}
//验证头插函数
void testSList2()
{
SLNode* plist = NULL;
SListPushFront(
SListPushFront(
SListPushFront(
SListPushFront(
SListPrint(plist);
}
//验证头删函数
void testSList3()
{
SLNode* plist = NULL;
SListPushBack(
SListPushBack(
SListPushBack(
SListPushBack(
SListPopFront(
SListPopFront(
SListPrint(plist);
}
//验证尾删函数
void testSList4()
{
SLNode* plist = NULL;
SListPushFront(
SListPushFront(
SListPushFront(
SListPushFront(
SListPopFront(
SListPopFront(
SListPrint(plist);
}
//验证给数据返回其所在节点地址的函数,和删除数据节点函数或插入数据节点之前的函数配合使用
void testSList5()
{
SLNode* plist = NULL;
SListPushBack(
SListPushBack(
SListPushBack(
SListPushBack(
SListFindDate(plist,2);
}
//验证在返回的节点地址pos前插入一个数据的函数
void testSList6()
{
SLNode* plist = NULL;
SListPushFront(
SListPushFront(
SListPushFront(
SListPushFront(
SListPushpos(&plist, 8, 1);
SListPrint(plist);
}
//验证给数据返回其所在节点地址,删除这个节点的函数
void testSList7()
{
SLNode* plist = NULL;
SListPushBack(
SListPushBack(
SListPushBack(
SListPushBack(
SListPopdate(
SListPopdate(
SListPrint(plist);
}
//验证给一个数据,找到这个数据所在的节点,并用新数据修改的函数
void testSList8()
{
SLNode* plist = NULL;
SListPushFront(
SListPushFront(
SListPushFront(
SListPushFront(
SListChangeDate(plist, 6, 9);
SListPrint(plist);
}
int main()
{
menu();
int input = 0;
do
{
fprintf(stdout, "请输入:>");
fscanf(stdin,"%d",
switch (input)
{
case 1:
testSList1();//进入尾插数据操作
fprintf(stdout, "尾插数据成功\n");
break;
case 2:
testSList2();//进入头插数据操作
fprintf(stdout, "头插数据成功\n");
break;
case 3:
testSList3();//进入头删数据操作
fprintf(stdout, "头删数据成功\n");
break;
case 4:
testSList4();//进入尾删数据操作
fprintf(stdout, "尾删数据成功\n");
break;
case 5:
testSList6();//进入随机插入数据操作
fprintf(stdout, "随机插入数据成功\n");
break;
case 6:
testSList7();//进入随机删除数据操作
fprintf(stdout, "随机删除数据成功\n");
break;
case 7:
testSList8();//进入修改数据操作
break;
case 0:
printf("退出\n");
break;
default:
fprintf(stdout, "选择错误,请重新选择\n");
}
} while (input);
}
2、头文件SList.h代码
#include<stdio.h>
#include<stdlib.h>
typedef int SLdatetype;//重定义类型名,这样可以修改想要的类型
typedef struct SListNode SLNode;//重定义结构体类型的名字
struct SListNode //单链表节点
{
SLdatetype date;
SLNode* next;
};
void SListPrint(SLNode* phead);//打印单链表
void SListPushBack(SLNode** pphead, SLdatetype x);//尾插函数
void SListPushFront(SLNode** pphead, SLdatetype x);//头插函数
void SListPopFront(SLNode** pphead);//头删函数
void SListPopBack(SLNode** pphead);//尾删函数
SLNode* SListFindDate(SLNode* phead, SLdatetype x);//验证给数据返回其所在节点地址的函数
void SListPushpos(SLNode** pphead, SLdatetype x, SLdatetype y);//在返回的节点地址pos前插入一个数据的函数,x是找的数据,y是插入的数据
void SListPopdate(SLNode** pphead, SLdatetype x);//给数据返回其所在节点地址,删除这个节点的函数
void SListChangeDate(SLNode* phead, SLdatetype x,SLdatetype y);//因为不需要改变节点的地址,所以值传递即可
//x是查找的数据,y是新数据,用来修改查找的数据
3、函数功能实现源文件 SList.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"
//打印单链表
void SListPrint(SLNode* phead)//实参是单链表的第一个节点的地址
{
while (phead != NULL)
{
printf("%d->", phead->date);
phead = phead->next;
}
printf("NULL\n");
}
//尾插函数
void SListPushBack(SLNode** pphead, SLdatetype x)
{
SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
newnode->date = x;
newnode->next = NULL;//创建一个新的节点
if (*pphead == NULL)//当没有节点的时候,这时候开辟的内存就给plist
{
*pphead = newnode;
}
else
{
SLNode* cru = *pphead;
while (cru->next != NULL)//这里必须改变节点里面的指针next存放的地址
{
cru = cru->next;
}
cru->next = newnode;//所以这里必须用cru->next访问这个指针才可以改变next存放的地址
}
}
//头插函数
void SListPushFront(SLNode** pphead, SLdatetype x)
{
SLNode* newcode = (SLNode*)malloc(sizeof(SLNode));
newcode->date = x;
newcode->next = NULL;
//if (*pphead == NULL)//当单链表里没有节点的时候
//{
// *pphead = newcode;
//}
//else
//{
newcode->next = *pphead;//这里已经包括了单链表没有节点的时候,所以可以不用上面if
*pphead = newcode;
//}
}
//头删函数 因为节点是动态开辟的,所以直接用free函数就能删除,
//一般来说释放空间后,指向这块空间的指针要置为空指针
void SListPopFront(SLNode** pphead)
{
if (*pphead != NULL)//如果空指针,即没有节点,那么就不需要删除
{
SLNode* next0 = (*pphead)->next;//这里也满足只有一个节点的情况
free(*pphead);
*pphead = next0;
}
}
//尾删函数 因为同样节点是动态开辟的,所以直接用free函数释放空间
void SListPopBack(SLNode** pphead)
{
if (*pphead)//如果单链表没有节点,即plist是空指针,就不进入尾删
{
SLNode* cru = *pphead;
SLNode* prev = NULL;
if((*pphead)->next==NULL)
{
free(*pphead);
*pphead = NULL;
}
while (cru->next != NULL)//新定义一个指针,得到尾删节点的前一个节点的地址
{
prev = cru;
cru = cru->next;
}
prev->next = NULL;
free(cru);
cru = NULL;
}
}
//给一个数据,返回这个数据所在节点的地址的函数
SLNode* SListFindDate(SLNode* phead, SLdatetype x)
//因为不需要改变指向第一个节点的指针的值,
//即不需要改变这个指针存放的地址
{
while (phead != NULL)//如果没有节点,根本不会进入循环去找
{
if (phead->date == x)
{
return phead;
}
else
{
phead = phead->next;
}
}
return NULL;
}
//在返回的节点地址pos前插入一个数据的函数
void SListPushpos(SLNode** pphead,SLdatetype x,SLdatetype y)
{
SLNode* prev = NULL;
SLNode* cru = *pphead;
SLNode* pos = SListFindDate(*pphead, x);
SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
newnode->date = y;
newnode->next = NULL;
if (pos != NULL)//如果是没找到这个数据,或者没有节点,就不随机插
{
while (cru != pos)
{
prev = cru;
cru = cru->next;
}
if (prev != NULL)
{
newnode->next = pos;
prev->next = newnode;
}
else
{
newnode->next = pos;
*pphead = newnode;
}
}
}
//给数据返回其所在节点地址,删除这个节点的函数
void SListPopdate(SLNode** pphead, SLdatetype x)
{
SLNode* cru = *pphead;
SLNode* prev = NULL;
SLNode* pos = SListFindDate(*pphead, x);
if (pos != NULL)//如果是没找到这个数据,或者没有节点,就不随机删
{
while (cru != pos)
{
prev = cru;
cru = cru->next;
}
if (prev != NULL)
{
prev->next = pos->next;
free(pos);
pos = NULL;
}
else
{
*pphead = pos->next;
free(cru);
cru = NULL;
}
}
}
//给一个数据,找到这个数据所在的节点,并用新数据修改
void SListChangeDate(SLNode* phead, SLdatetype x,SLdatetype y)
//因为不需要改变节点的地址,所以值传递即可
//x是查找的数据,y是新数据,用来修改查找的数据
{
SLNode* cru = phead;
while (cru != NULL)//如果没有节点,根本不会进入循环去找
{
if (cru->date == x)
{
cru->date = y;
break;//修改完数据后,就跳出循环
}
else
{
cru = cru->next;
}
}
if (cru == NULL)//如果循环完单链表,没有找到要修改的那个数据
{
fprintf(stdout, "要修改的数据不存在,请重新修改数据\n");
}
else
{
fprintf(stdout, "修改成功\n");
}
}
四、代码运行实例展示