目录
一、顺序表的问题及思考
二、链表的概念及结构
三、单链表的实现
3.1 增
3.1.1 尾插
3.1.2 头插
3.1.3 指定位置前插入
3.1.4 指定位置后插入
3.2 删
3.2.1 尾删
3.2.2 头删
3.2.3 指定位置删除
3.2.4 指定位置后删除
3.2.5 链表的销毁
3.3 查
3.4 改
四、完整代码
一、顺序表的问题及思考
1.1
中间/头部的插⼊删除,时间复杂度为O(N)
1.2
增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
1.3
增容⼀般是呈2倍的增长,势必会有⼀定的空间浪费。例如当前容量为
100,满了以后增容到 200,我们再继续插⼊了5个数据,
后面没有数据插入了,那么就浪费了95个数据空间。
二、链表的概念及结构
#include<stdio.h>
typedef int luck;//存储不同类型数据,重命名,这样后面就只用改这里的int
struct SListNOde
{
luck data;//存储的数据
SListNOde* next;//指向下一个节点的指针
};
SLNO* SLNOIn()//节点申请空间
{
SLNO* newnode = (SLNO*)malloc(sizeof(SLNO));
if (newnode == NULL)
{
perror("malloc fail");
exit(1);
}
return newnode;
}
不要忘了强制类型转换成节点类型
void SLNOprint(SLNO* phead)
{
SLNO* pres = phead;
while (pres)//节点处不是空指针就有数据
{
printf("%d->", pres->data);
pres = pres->next;
}
printf("NULL\n");
}
void test01()
{
SLNO* n1 = SLNOIn();
n1->data = 1;
n1->next = NULL;
SLNOprint(n1);
}
int main()
{
test01();
return 0;
}
再多弄几个节点
void test02()
{
SLNO* phead = NULL;
SLNO* n1;
SLNO* n2;
SLNO* n3;
SLNO* n4;
n1 = SLNOIn();
n2 = SLNOIn();
n3 = SLNOIn();
n4 = SLNOIn();
phead = n1;//指向第一个节点的指针
n1->data = 1;
n2->data = 2;
n3->data = 3;
n4->data = 4;
n1->next = n2;
n2->next = n3;
n3->next = n4;
n4->next = NULL;
SLNOprint(phead);
}
int main()
{
test02();
return 0;
}
目前测试着是可行的,接下来实现单链表
三、单链表的实现
3.1 增
与顺序表类似,往链表中插入额外的数据
3.1.1 尾插
将一个新的节点插入到链表尾部。
(图中所列地址仅为方便展示而顺手写的)
那么首先我们需要找到尾节点
那么判断是否是尾节点的条是?
通过该图我们可以看出,尾节点中的指针是NULL
那么判断条件就是
SLNO* pres = phead;
while (pres->next)
{
pres = pres->next;//尾部节点是该节点保存的下个节点地址为NULL
}
同时,因为需要在原链表中新增一个节点
所以需要进行空间申请
在这之后,空间申请成功后,这块空间的地址需要由原尾节点进行保存
依此,我们可以写出如下函数
void SLNOInsertback(SLNO* phead, luck X)
{
SLNO* pres = pphead;//用来查找尾
SLNO* newnode = SLNOIn();
newnode->data = X;
newnode->next = NULL;
//要从尾部进行插入,那就要找到尾部节点
while (pres->next)
{
pres = pres->next;//尾部节点是该节点保存的下个节点地址为NULL
}
pres->next = newnode;//申请一个新节点
}
那么这里只是就链表中已经有数据的情况写出这个函数
如果拿到的链表是一个空链表,那么进行pres->next就肯定会报错,不能对NULL进行解应用
那就单独判断一下
无论是哪种情况,插入一个数据肯定都是要申请一个新节点的
void SLNOInsertback(SLNO* phead, luck X)
{
SLNO* pres = phead;//用来查找尾
SLNO* newnode = SLNOIn();//申请一个新节点
newnode->data = X;
newnode->next = NULL;
//如果拿到的链表是一个空链表,那么进行pres->next就肯定会报错,不能对NULL进行解应用
//那就单独判断一下
//如果是这种情况,那么就直接申请一个新节点就好了
if (pres == NULL)
{
phead = SLNOIn();
return;
}
//要从尾部进行插入,那就要找到尾部节点
while (pres->next)
{
pres = pres->next;//尾部节点是该节点保存的下个节点地址为NULL
}
pres->next = newnode;
}
测试一下
void test03()
{
SLNO* phead = NULL;
SLNOInsertback(phead,3);
SLNOprint(phead);
}
int main()
{
test03();
return 0;
}
这里可以看到出现了问题,调试看下是个什么情况
这里可以看到
newnode的值改变了,但是phead的值没有改变
即只改变了形参的值,没有改变实参的值
说明这里是传值调用,我们需要用传址调用
这里phead自身是个指针变量,那么要存放一级指针变量的地址,就要使用二级指针接收。
对应的函数也需要做出改变。
void SLNOInsertback(SLNO** pphead, luck X)
{
assert(pphead);
SLNO* pres = *pphead;//用来查找尾
SLNO* newnode = SLNOIn();
newnode->data = X;
newnode->next = NULL;
//如果拿到的链表是一个空链表,那么进行pres->next就肯定会报错,不能对NULL进行解应用
//那就单独判断一下
//如果是这种情况,那么就直接申请一个新节点就好了
if (pres == NULL)
{
*pphead = newnode;
return;
}
//要从尾部进行插入,那就要找到尾部节点
while (pres->next)
{
pres = pres->next;//尾部节点是该节点保存的下个节点地址为NULL
}
pres->next = newnode;
}
void test03()
{
SLNO* phead = NULL;
SLNOInsertback(&phead, 3);
SLNOInsertback(&phead, 4);
SLNOInsertback(&phead, 5);
SLNOInsertback(&phead, 6);
SLNOInsertback(&phead, 7);
SLNOprint(phead);
}
int main()
{
test03();
return 0;
}
这会儿可以看到,是成功输出出来了
3.1.2 头插
即把数据从链表的头部进行插入
插入的这个新结点作为链表的头部节点
(图中所列地址仅为方便展示而顺手写的)
如图,插入该节点后,首节点就是这个新插入的节点,这个节点的指针保存的就是原首节点的地址
//头部数据插入
void SLNOInsertfront(SLNO** pphead, luck X)
{
assert(pphead);
SLNO* pres = *pphead;//保存头节点的位置
SLNO* newnode = SLNOIn();//申请空间
newnode->data = X;
newnode->next = pres;
*pphead = newnode;
}
在这里就不用判断要插入数据的链表为不为空了,因为是直接从头部插入,不需要查找节点
测试一下
void test04()
{
SLNO* phead = NULL;
SLNOInsertfront(&phead, 3);
SLNOInsertfront(&phead, 4);
SLNOInsertfront(&phead, 5);
SLNOInsertfront(&phead, 6);
SLNOprint(phead);
}
int main()
{
test04();
return 0;
}
是可行的
3.1.3 指定位置前插入
在某一个指定位置前插入,首先需要找到该指定位置,该位置的前一节点的指向新插入的节点,
原指向节点为新插入位置所指向的节点
(图中所列地址仅为方便展示而顺手写的)
void SLNOInsertbefore(SLNO** pphead, SLNO* pos, luck X)
{
assert(pphead && pos);//要插入的位置肯定不能为空
SLNO* pres = *pphead;
SLNO* newnode = SLNOIn();//申请新节点
while (pres->next != pos)
{
pres = pres->next;
}//找插入位置前的那个节点
SLNO* temp = pres->next;//保存插入位置前节点指向的下一个节点的指针
newnode->data = X;
newnode->next = temp;//原指向节点为新插入位置所指向的节点
pres->next = newnode;//让插入为位置前节点的指向变更为插入的节点
}
这里,由于是链表,pos是一个指针,我们需要找到我们想要插入数据的位置就要先将对应的地址找
出来,这里再来一个find函数
SLNO* Find(SLNO* phead, luck num)
{
SLNO* pres = phead;
while (num != pres->data && pres != NULL)
{
pres = pres->next;
}
if (pres == NULL)
{
return NULL;
}
return pres;
}
测试一下
void test03()
{
SLNO* phead = NULL;
SLNOInsertback(&phead, 3);
SLNOInsertback(&phead, 4);
SLNOInsertback(&phead, 5);
SLNOInsertback(&phead, 6);
SLNOInsertback(&phead, 7);
SLNOprint(phead);
SLNO* find = Find(phead, 4);
SLNOInsertbefore(&phead, find, 10);
SLNOprint(phead);
find = Find(phead, 7);
SLNOInsertbefore(&phead, find, 9);
SLNOprint(phead);
}
这次测试没有问题,我们再来看一组测试
void test04()
{
SLNO* phead = NULL;
SLNOInsertfront(&phead, 3);
SLNOInsertfront(&phead, 4);
SLNOInsertfront(&phead, 5);
SLNOInsertfront(&phead, 6);
SLNOInsertbefore(&phead, phead, 10);
SLNOprint(phead);
}
int main()
{
test04();
return 0;
}
可以看到代码异常退出了
这里调试看看
通过调试可以看出,这里的错误是对空指针解应用了
回到代码的逻辑
想在头节点前插入一个节点,那么pos就是直接传的头节点phead,在代码的判定逻辑中,在
循环判定这个位置就不能找到pos。
我们发现这里的插入实际上就是前文所写的头插,那我们在进行插入时进行判断,如果是这种
情况调用一下头插函数就好了
void SLNOInsertbefore(SLNO** pphead, SLNO* pos, luck X)
{
assert(pphead && pos);//要插入的位置肯定不能为空
SLNO* pres = *pphead;
if (pos == pres)
{
SLNOInsertfront(pphead, X);
return;
}
SLNO* newnode = SLNOIn();//申请新节点
while (pres->next != pos)
{
pres = pres->next;
}//找插入位置前的那个节点
SLNO* temp = pres->next;//保存插入位置前节点指向的下一个节点的指针
newnode->data = X;
newnode->next = temp;//原指向节点为新插入位置所指向的节点
pres->next = newnode;//让插入为位置前节点的指向变更为插入的节点
}
在测试一下
void test04()
{
SLNO* phead = NULL;
SLNOInsertfront(&phead, 3);
SLNOInsertfront(&phead, 4);
SLNOInsertfront(&phead, 5);
SLNOInsertfront(&phead, 6);
SLNOInsertbefore(&phead, phead, 1);
SLNOprint(phead);
}
int main()
{
test04();
return 0;
}
这样就解决了。
3.1.4 指定位置后插入
所插入位置的节点指针更改为指向这个插入的节点,原指向位置由插入的新节点指向
(图中所列地址仅为方便展示而顺手写的)
//插入指定位置后
void SLNOInsertafter(SLNO** pphead, SLNO* pos, luck X)
{
assert(*pphead && pos);
SLNO* pres = *pphead;
SLNO* newnode = SLNOIn();
while (pres != pos)
{
pres = pres->next;
}//找到插入节点
SLNO* temp = pres->next;//保存插入原指向位置
newnode->data = X;
newnode->next = temp;
pres->next = newnode;
}
测试一下
void test05()
{
SLNO* phead = NULL;
SLNOInsertback(&phead, 3);
SLNOInsertback(&phead, 4);
SLNOInsertback(&phead, 5);
SLNOInsertback(&phead, 6);
SLNOInsertback(&phead, 7);
SLNOprint(phead);
SLNO* find = Find(phead, 4);
SLNOInsertafter(&phead, find, 10);
SLNOprint(phead);
find = Find(phead, 7);
SLNOInsertafter(&phead, find, 9);
SLNOprint(phead);
SLNOInsertafter(&phead, phead, 1);
SLNOprint(phead);
}
int main()
{
test05();
return 0;
}
可以看到这里没有问题
3.2 删
将一个节点删除,实际上就是将该节点所申请的空间释放掉。
3.2.1 尾删
从链表的尾部进行删除
将尾部节点释放后,指向尾部节点的这个节点现在指向需要变更为NULL
(图中所列地址仅为方便展示而顺手写的)
void SLNOdelback(SLNO** pphead)
{
assert(*pphead && pphead);//要进行删除操作,链表肯定不能为空
SLNO* pres = *pphead;
while (pres->next->next != NULL)
{
pres = pres->next;//找尾节点之前的那个节点
}
free(pres->next->next);//释放尾节点
pres->next->next = NULL;//将指向尾节点的节点指向置空
pres->next = NULL;
}
void test06()
{
SLNO* phead = NULL;
SLNOInsertback(&phead, 3);
SLNOInsertback(&phead, 4);
SLNOInsertback(&phead, 5);
SLNOInsertback(&phead, 6);
SLNOInsertback(&phead, 7);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);
}
int main()
{
test06();
return 0;
}
这里的测试没有问题
void test06()
{
SLNO* phead = NULL;
SLNOInsertback(&phead, 3);
SLNOInsertback(&phead, 4);
SLNOInsertback(&phead, 5);
SLNOInsertback(&phead, 6);
SLNOInsertback(&phead, 7);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);
}
int main()
{
test06();
return 0;
}
这里看到出现了错误
前面几次函数都能正常运行
可见问题是出现在最后依次删除
void test06()
{
SLNO* phead = NULL;
SLNOInsertback(&phead, 3);
/*SLNOInsertback(&phead, 4);
SLNOInsertback(&phead, 5);
SLNOInsertback(&phead, 6);
SLNOInsertback(&phead, 7);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);*/
SLNOdelback(&phead);
SLNOprint(phead);
}
int main()
{
test06();
return 0;
}
进行一下调试
这里可以看到错误是对空指针解应用,说明该函数在对链表仅剩一个节点时存在漏洞,这里进行一
下改进
void SLNOdelback(SLNO** pphead)
{
assert(*pphead && pphead);//要进行删除操作,链表肯定不能为空
SLNO* pres = *pphead;
if (pres->next == NULL)
{
free(pres);
*pphead = NULL;
return;
}//判断是不是头节点
while (pres->next->next != NULL)
{
pres = pres->next;//找尾节点之前的那个节点
}
free(pres->next->next);//释放尾节点
pres->next->next = NULL;//将指向尾节点的节点指向置空
pres->next = NULL;
}
void test06()
{
SLNO* phead = NULL;
SLNOInsertback(&phead, 3);
SLNOInsertback(&phead, 4);
SLNOInsertback(&phead, 5);
SLNOInsertback(&phead, 6);
SLNOInsertback(&phead, 7);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);
}
int main()
{
test06();
return 0;
}
这样就可以了
3.2.2 头删
从链表的头部进行删除
首节点指向的节点成为新的首节点
(图中所列地址仅为方便展示而顺手写的)
void test07()
{
SLNO* phead = NULL;
SLNOInsertback(&phead, 3);
SLNOInsertback(&phead, 4);
SLNOInsertback(&phead, 5);
SLNOInsertback(&phead, 6);
SLNOInsertback(&phead, 7);
SLNOprint(phead);
SLNOdelfront(&phead);
SLNOprint(phead);
SLNOdelfront(&phead);
SLNOprint(phead);
SLNOdelfront(&phead);
SLNOprint(phead);
SLNOdelfront(&phead);
SLNOprint(phead);
SLNOdelfront(&phead);
SLNOprint(phead);
}
int main()
{
test07();
return 0;
}
可以看到是可行的
3.2.3 指定位置删除
删除指定位置
删除后,该位置前的节点指向该位置之后的节点
(图中所列地址仅为方便展示而顺手写的)
void SLNOdel(SLNO** pphead, SLNO* pos)
{
assert(pphead && *pphead);//要删除的链表不能为空
assert(pos);//要删除的位置不能为空
SLNO* pres = *pphead;
while (pres->next != pos)
{
pres = pres->next;
}//找删除位置的上一个节点
pres->next = pos->next;//让pos的前一个节点指向pos的后一个节点
free(pos);
pos = NULL;
}
void test08()
{
SLNO* phead = NULL;
SLNOInsertback(&phead, 3);
SLNOInsertback(&phead, 4);
SLNOInsertback(&phead, 5);
SLNOInsertback(&phead, 6);
SLNOInsertback(&phead, 7);
SLNOprint(phead);
SLNO* find = Find(phead, 4);
SLNOdel(&phead, find);
SLNOprint(phead);
find = Find(phead, 7);
SLNOdel(&phead, find);
SLNOprint(phead);
}
int main()
{
test08();
return 0;
}
这里测试着是没啥问题
测试一下首节点
void test08()
{
SLNO* phead = NULL;
SLNOInsertback(&phead, 3);
SLNOInsertback(&phead, 4);
SLNOInsertback(&phead, 5);
SLNOInsertback(&phead, 6);
SLNOInsertback(&phead, 7);
SLNOprint(phead);
SLNO* find = Find(phead, 4);
SLNOdel(&phead, find);
SLNOprint(phead);
find = Find(phead, 7);
SLNOdel(&phead, find);
SLNOprint(phead);
SLNOdel(&phead, phead);
SLNOprint(phead);
}
int main()
{
test08();
return 0;
}
代码异常退出了,调试看看
对空指针解应用了
优化一下针对首节点这种情况
//任意位置删除
void SLNOdel(SLNO** pphead, SLNO* pos)
{
assert(pphead && *pphead);//要删除的链表不能为空
assert(pos);//要删除的位置不能为空
SLNO* pres = *pphead;
if (pres == pos)
{
*pphead = pres->next;//让首节点指向的节点成为新的首节点
free(pres);
pres = NULL;
return;
}//判断是不是首节点
while (pres->next != pos)
{
pres = pres->next;
}//找删除位置的上一个节点
pres->next = pos->next;//让pos的前一个节点指向pos的后一个节点
free(pos);
pos = NULL;
}
void test08()
{
SLNO* phead = NULL;
SLNOInsertback(&phead, 3);
SLNOInsertback(&phead, 4);
SLNOInsertback(&phead, 5);
SLNOInsertback(&phead, 6);
SLNOInsertback(&phead, 7);
SLNOprint(phead);
SLNO* find = Find(phead, 4);
SLNOdel(&phead, find);
SLNOprint(phead);
find = Find(phead, 7);
SLNOdel(&phead, find);
SLNOprint(phead);
SLNOdel(&phead, phead);
SLNOprint(phead);
}
int main()
{
test08();
return 0;
}
这样就可行了
3.2.4 指定位置后删除
将指定位置后的那个节点删除
指定位置指向被删除节点所指向的节点
(图中所列地址仅为方便展示而顺手写的)
pos不能是个空指针,且pos后的这个节点不能为空
void SLNOdelafter(SLNO** pphead, SLNO* pos)//任意位置后删除
{
assert(pphead && *pphead);
SLNO* pres = *pphead;
while (pres != pos)
{
pres = pres->next;
}//找到pos
SLNO* temp = pres->next->next;//pos后的节点所指向节点
free(pres->next);//释放pos后的一个节点
pres->next = temp;//pos指向被删除的节点所指向的节点
}
void test10()
{
SLNO* phead = NULL;
SLNOInsertback(&phead, 3);
SLNOInsertback(&phead, 4);
SLNOInsertback(&phead, 5);
SLNOInsertback(&phead, 6);
SLNOInsertback(&phead, 7);
SLNOprint(phead);
SLNO* find = Find(phead, 4);
SLNOdelafter(&phead, find);
SLNOprint(phead);
SLNOdelafter(&phead, phead);
SLNOprint(phead);
//find = Find(phead, 7);
//SLNOdelafter(&phead, find);
// SLNOprint(phead);
}
int main()
{
test10();
return 0;
}
3.2.5 链表的销毁
链表是动态申请来的空间,那肯定就会有释放
将所有节点都释放,链表就被销毁了
在进行一个节点的释放的时候,要先将该节点指向的下一个节点的地址先保存起来
void SLNODestory(SLNO** pphead)
{
assert(pphead && *pphead);
SLNO* pres = *pphead;
while (pres)
{
SLNO* temp = pres->next;//保存下一节点的地址
free(pres);
pres = NULL;//释放
pres = temp;//再到下个节点
}
*pphead = NULL;//最后再让头节点置空
return;
}
void test09()
{
SLNO* phead = NULL;
SLNOInsertback(&phead, 3);
SLNOInsertback(&phead, 4);
SLNOInsertback(&phead, 5);
SLNOInsertback(&phead, 6);
SLNOInsertback(&phead, 7);
SLNOprint(phead);
SLNODestory(&phead);
SLNOprint(phead);
}
int main()
{
test09();
return 0;
}
可以看到也是可行的
3.3 查
在指定位置插入删除的函数中已经说过了,这里就不再赘述
SLNO* Find(SLNO* phead, luck num)
{
SLNO* pres = phead;
while (num != pres->data && pres != NULL)
{
pres = pres->next;
}
if (pres == NULL)
{
return NULL;
}
return pres;
}
3.4 改
找到要修改的位置进行修改就好了
void SLNOmodify(SLNO** pphead, SLNO* pos, luck X)
{
assert(pphead && *pphead);
assert(pos);
SLNO* pres = *pphead;
while (pres != pos)
{
pres = pres->next;
}
pres->data = X;
}
void test11()
{
SLNO* phead = NULL;
SLNOInsertback(&phead, 3);
SLNOInsertback(&phead, 4);
SLNOInsertback(&phead, 5);
SLNOInsertback(&phead, 6);
SLNOInsertback(&phead, 7);
SLNOprint(phead);
SLNO* find = Find(phead, 4);
SLNOmodify(&phead, find, 2);
SLNOprint(phead);
}
int main()
{
test11();
return 0;
}
四、完整代码
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
//Seqlist.h
typedef int luck;//存储不同类型数据,重命名,这样后面就只用改这里的int
struct SListNOde
{
luck data;//存储的数据
struct SListNOde* next;//指向下一个节点的指针
};
typedef struct SListNOde SLNO;
void SLNOprint(SLNO* phead);//打印每个节点处的数据
SLNO* SLNOIn();//初始化节点
void SLNOInsertback(SLNO** pphead, luck X);//单链表的尾插
void SLNOInsertfront(SLNO** pphead, luck X);//单链表的头插
void SLNOInsertbefore(SLNO** pphead, SLNO* pos, luck X);//任意位置前插入
SLNO* Find(SLNO* phead, luck num);//这是查找函数
void SLNOInsertafter(SLNO** pphead, SLNO* pos, luck X);//任意位置后插入
void SLNOdelback(SLNO** pphead);//尾删
void SLNOdelfront(SLNO** pphead);//头删
void SLNOdel(SLNO** pphead, SLNO* pos);//任意位置删除
void SLNOdelafter(SLNO** pphead, SLNO* pos);//任意位置后删除
void SLNODestory(SLNO** pphead);//链表的销毁
void SLNOmodify(SLNO** pphead, SLNO* pos, luck X);//链表的修改
#include"Seqlist.h"
//Seqlist.c
//打印每个节点处的数据
void SLNOprint(SLNO* phead)
{
SLNO* pres = phead;
while (pres)//节点处不是空指针就有数据
{
printf("%d->", pres->data);
pres = pres->next;
}
printf("NULL\n");
}
SLNO* SLNOIn()//节点申请空间
{
SLNO* newnode = (SLNO*)malloc(sizeof(SLNO));
if (newnode == NULL)
{
perror("malloc fail");
exit(1);
}
return newnode;
}
//尾插数据
void SLNOInsertback(SLNO** pphead, luck X)
{
assert(pphead);
SLNO* pres = *pphead;//用来查找尾
SLNO* newnode = SLNOIn();
newnode->data = X;
newnode->next = NULL;
//如果拿到的链表是一个空链表,那么进行pres->next就肯定会报错,不能对NULL进行解应用
//那就单独判断一下
//如果是这种情况,那么就直接申请一个新节点就好了
if (pres == NULL)
{
*pphead = newnode;
return;
}
//要从尾部进行插入,那就要找到尾部节点
while (pres->next)
{
pres = pres->next;//尾部节点是该节点保存的下个节点地址为NULL
}
pres->next = newnode;
}
//头部数据插入
void SLNOInsertfront(SLNO** pphead, luck X)
{
assert(pphead);
SLNO* pres = *pphead;//保存头节点的位置
SLNO* newnode = SLNOIn();//申请空间
newnode->data = X;
newnode->next = pres;
*pphead = newnode;
}
//查找节点位置
SLNO* Find(SLNO* phead, luck num)
{
SLNO* pres = phead;
while (pres != NULL && num != pres->data )
{
pres = pres->next;//找到要查找数据的地址
}
if (pres == NULL)
{
return NULL;//为空了说明链表中没有要查找的数据
}
return pres;
}
//插入指定位置前
void SLNOInsertbefore(SLNO** pphead, SLNO* pos, luck X)
{
assert(pphead && pos && *pphead);//要插入的位置肯定不能为空
SLNO* pres = *pphead;
if (pos == pres)
{
SLNOInsertfront(pphead, X);
return;
}//如果是在首节点处插入就直接调用头插函数了
SLNO* newnode = SLNOIn();//申请新节点
while (pres->next != pos)
{
pres = pres->next;
}//找插入位置前的那个节点
SLNO* temp = pres->next;//保存插入位置前节点指向的下一个节点的指针
newnode->data = X;
newnode->next = temp;//原指向节点为新插入位置所指向的节点
pres->next = newnode;//让插入为位置前节点的指向变更为插入的节点
}
//插入指定位置后
void SLNOInsertafter(SLNO** pphead, SLNO* pos, luck X)
{
assert(*pphead && pos);
SLNO* pres = *pphead;
SLNO* newnode = SLNOIn();
while (pres != pos)
{
pres = pres->next;
}//找到插入节点
SLNO* temp = pres->next;//保存插入原指向位置
newnode->data = X;
newnode->next = temp;
pres->next = newnode;
}
//尾删
void SLNOdelback(SLNO** pphead)
{
assert(*pphead && pphead);//要进行删除操作,链表肯定不能为空
SLNO* pres = *pphead;
if (pres->next == NULL)
{
free(pres);
*pphead = NULL;
return;
}//判断是不是头节点
while (pres->next->next != NULL)
{
pres = pres->next;//找尾节点之前的那个节点
}
free(pres->next->next);//释放尾节点
pres->next->next = NULL;//将指向尾节点的节点指向置空
pres->next = NULL;
}
//头删
void SLNOdelfront(SLNO** pphead)
{
assert(pphead && *pphead);//要删除链表不能为空
SLNO* pres = *pphead;
*pphead = pres->next;//让首节点指向的节点成为新的节点
free(pres);//释放原首节点
pres = NULL;
}
//任意位置删除
void SLNOdel(SLNO** pphead, SLNO* pos)
{
assert(pphead && *pphead);//要删除的链表不能为空
assert(pos);//要删除的位置不能为空
SLNO* pres = *pphead;
if (pres == pos)
{
*pphead = pres->next;//让首节点指向的节点成为新的首节点
free(pres);
pres = NULL;
return;
}//判断是不是首节点
while (pres->next != pos)
{
pres = pres->next;
}//找删除位置的上一个节点
pres->next = pos->next;//让pos的前一个节点指向pos的后一个节点
free(pos);
pos = NULL;
}
//指定位置后删除
void SLNOdelafter(SLNO** pphead, SLNO* pos)
{
assert(pphead && *pphead);
assert(pos->next);
SLNO* pres = *pphead;
while (pres != pos)
{
pres = pres->next;
}//找到pos
SLNO* temp = pres->next->next;//pos后的节点所指向节点
free(pres->next);//释放pos后的一个节点
pres->next = temp;//pos指向被删除的节点所指向的节点
}
//链表的销毁
void SLNODestory(SLNO** pphead)
{
assert(pphead && *pphead);
SLNO* pres = *pphead;
while (pres)
{
SLNO* temp = pres->next;//保存下一节点的地址
free(pres);
pres = NULL;//释放
pres = temp;//再到下个节点
}
*pphead = NULL;//最后再让头节点置空
return;
}
void SLNOmodify(SLNO** pphead, SLNO* pos, luck X)
{
assert(pphead && *pphead);
assert(pos);
SLNO* pres = *pphead;
while (pres != pos)
{
pres = pres->next;
}
pres->data = X;
}
#include"Seqlist.h"
//test.c
void test01()
{
SLNO* n1 = SLNOIn();
n1->data = 1;
n1->next = NULL;
SLNOprint(n1);
}
void test02()
{
SLNO* phead = NULL;
SLNO* n1;
SLNO* n2;
SLNO* n3;
SLNO* n4;
n1 = SLNOIn();
n2 = SLNOIn();
n3 = SLNOIn();
n4 = SLNOIn();
phead = n1;//指向第一个节点的指针
n1->data = 1;
n2->data = 2;
n3->data = 3;
n4->data = 4;
n1->next = n2;
n2->next = n3;
n3->next = n4;
n4->next = NULL;
SLNOprint(phead);
}
void test03()
{
SLNO* phead = NULL;
SLNOInsertback(&phead, 3);
SLNOInsertback(&phead, 4);
SLNOInsertback(&phead, 5);
SLNOInsertback(&phead, 6);
SLNOInsertback(&phead, 7);
SLNOprint(phead);
SLNO* find = Find(phead, 4);
SLNOInsertbefore(&phead, find, 10);
SLNOprint(phead);
find = Find(phead, 7);
SLNOInsertbefore(&phead, find, 9);
SLNOprint(phead);
}
void test04()
{
SLNO* phead = NULL;
SLNOInsertbefore(&phead, phead, 1);
//SLNOInsertfront(&phead, 3);
//SLNOInsertfront(&phead, 4);
//SLNOInsertfront(&phead, 5);
//SLNOInsertfront(&phead, 6);
SLNOprint(phead);
}
void test05()
{
SLNO* phead = NULL;
SLNOInsertback(&phead, 3);
SLNOInsertback(&phead, 4);
SLNOInsertback(&phead, 5);
SLNOInsertback(&phead, 6);
SLNOInsertback(&phead, 7);
SLNOprint(phead);
SLNO* find = Find(phead, 4);
SLNOInsertafter(&phead, find, 10);
SLNOprint(phead);
find = Find(phead, 7);
SLNOInsertafter(&phead, find, 9);
SLNOprint(phead);
SLNOInsertafter(&phead, phead, 1);
SLNOprint(phead);
}
void test06()
{
SLNO* phead = NULL;
SLNOInsertback(&phead, 3);
SLNOInsertback(&phead, 4);
SLNOInsertback(&phead, 5);
SLNOInsertback(&phead, 6);
SLNOInsertback(&phead, 7);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);
SLNOdelback(&phead);
SLNOprint(phead);
}
void test07()
{
SLNO* phead = NULL;
SLNOInsertback(&phead, 3);
SLNOInsertback(&phead, 4);
SLNOInsertback(&phead, 5);
SLNOInsertback(&phead, 6);
SLNOInsertback(&phead, 7);
SLNOprint(phead);
SLNOdelfront(&phead);
SLNOprint(phead);
SLNOdelfront(&phead);
SLNOprint(phead);
SLNOdelfront(&phead);
SLNOprint(phead);
SLNOdelfront(&phead);
SLNOprint(phead);
SLNOdelfront(&phead);
SLNOprint(phead);
}
void test08()
{
SLNO* phead = NULL;
SLNOInsertback(&phead, 3);
SLNOInsertback(&phead, 4);
SLNOInsertback(&phead, 5);
SLNOInsertback(&phead, 6);
SLNOInsertback(&phead, 7);
SLNOprint(phead);
SLNO* find = Find(phead, 4);
SLNOdel(&phead, find);
SLNOprint(phead);
find = Find(phead, 7);
SLNOdel(&phead, find);
SLNOprint(phead);
SLNOdel(&phead, phead);
SLNOprint(phead);
}
void test09()
{
SLNO* phead = NULL;
SLNOInsertback(&phead, 3);
SLNOInsertback(&phead, 4);
SLNOInsertback(&phead, 5);
SLNOInsertback(&phead, 6);
SLNOInsertback(&phead, 7);
SLNOprint(phead);
SLNODestory(&phead);
SLNOprint(phead);
}
void test10()
{
SLNO* phead = NULL;
SLNOInsertback(&phead, 3);
SLNOInsertback(&phead, 4);
SLNOInsertback(&phead, 5);
SLNOInsertback(&phead, 6);
SLNOInsertback(&phead, 7);
SLNOprint(phead);
SLNO* find = Find(phead, 4);
SLNOdelafter(&phead, find);
SLNOprint(phead);
SLNOdelafter(&phead, phead);
SLNOprint(phead);
//find = Find(phead, 7);
//SLNOdelafter(&phead, find);
// SLNOprint(phead);
}
void test11()
{
SLNO* phead = NULL;
SLNOInsertback(&phead, 3);
SLNOInsertback(&phead, 4);
SLNOInsertback(&phead, 5);
SLNOInsertback(&phead, 6);
SLNOInsertback(&phead, 7);
SLNOprint(phead);
SLNO* find = Find(phead, 4);
SLNOmodify(&phead, find, 2);
SLNOprint(phead);
}
int main()
{
test11();
return 0;
}