循环链表4

它什么时候是申请结点,什么时候又是定义一个指针?

怎么区分它是在申请结点(申请结点一般都有malloc),还是在定义指针

可以把它类比为  int *,int *就是定义一个整型指针,换成Node *,就是定义一个Node类型(自己定义的类型)(长成Node的样子)的指针

Node的样子:

CNode* p = (CNode*)malloc(sizeof(CNode));

malloc的原本用法就是malloc前面有一个void*的指针,因为malloc申请出来的结点需要一个指针去指向它,才能让这个新结点被找到,但这个指针没有返回值,没有名字,所以在后面sizeof里面写完你要定义的结点类型后,前面对应的就要强转类型了。        最后等号左边给同类型的指针起一个名字来接收这个结点。

而这句话的意思是,有(定义)一个指针p,指向这个(新申请的)Node结点

也可以说,定义一个指针p,接收一下结点的返回值

这里的Node *是其强转类型的作用,malloc的原本类型是void *,无返回值

而这个就是直接定义一个头结点,没有指针*

所以只要有Node*(除了强转类型)就是定义指针,只是看它有没有接收结点,接收了结点的话后面写它就是代指其接收的结点,也就是p表示一个结点,p和p的next的实际值就是那一长串数字地址,将数字地址赋值也就是改变指针指向,而地址必须要存起来,否则链条就会断掉

这2句话的意思是将刚定义的头结点初始化置成空结点

然后是在链表里面的遍历循环,改变结构要依靠前驱就初始化为plist,单纯查找输出就初始化为plist的next。

查找函数——在链表plist中 查找第一个key值,找到返回key值的结点地址,没有找到返回空NULL

测试

删除函数——删除第一个val的值(考点)

删除函数一定会依赖前驱(穿透),所以第一步是先查找前驱

查找前驱函数——返回key的前驱地址,如果不存在(key无前驱,在表头)返回NULL

例如,如图找数字3的前驱即p所指位置

穿透如图所示

测试

删除函数——删除pos位置的值(跟链表一样)

测试

返回key的后继下标函数——如果不存在(key无后继,在表尾)返回NULL

清空链表中的数据函数

销毁整个链表内存函数(交回)

如图,销毁是将结点挨个一个一个的删除了销毁,所以这个算法也叫总是删除第一个结点。

删除一个结点的函数就是要找这个结点的前驱(每一次找前驱都要从头到尾遍历一遍),所以倒着从末尾结点开始删除就会复杂化,时间复杂度太大,但也能实现。

总是删除第一个结点,就是——先定义一个p,指向plist->next,(这里的p相当于删除函数中起暂保存的q的作用),然后p逐渐向后移动,逐个结点穿透删除。

即plist后面只要有结点(就是第一个结点)(也就是plist->next!=NULL)就删除它

(也可以总是删除第二个结点,最后再删除第一个结点,时间复杂度同样,这就是代码的多样性)

测试

代码为0即正常没有崩溃,否则会显示一个负数

销毁完成后还剩下一个头结点plist是不用销毁的

如图,因为在测试前面定义的头结点head就不是malloc出来的,且初始化里面也没有malloc

所以这里的head头结点就是一个临时变量,不用free

如果初始化里面malloc了(此时外面就不用定义临时变量了,但需要定义一个指针接收一下),那么销毁函数里面的头结点也要free一下,否则会内存泄漏。所以没有必要malloc,临时变量就好

循环链表与单链表的区别就是表尾的next为plist还是NULL,循环链表中不能出现NULL,出现就死循环了,因为循环链表本身就是一个环,里面没有找不到NULL.

而头插,尾插,按val值删除三个的时间复杂度跟前面单链表还一样,头插是O(1),头删也是O(1),尾插(for找尾巴)是O(n),尾删也是O(n)

  • 25
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值