接着上次的内容,我们继续!

还是无头单向非循环链表。假如要删除某个节点,如何实现?

//删除成功返回0,失败返回-1
int slist_del(struct node_info *node, struct slist_info *info)
{
assert(info != NULL && node != NULL);
assert(!slist_is_empty(info));
if(node==info->first)//如果要删除的就是第一个节点
{
info->first = node->next;
free(node);
return 0;
}
//如果不是第一个,那么是哪个呢?要删除必须先找到,可是找到就可以了吗?
//因为是单向链表,我们只能知道这个节点的后面那个,而不知道前面是谁,那怎么删除呢?
//所以,在遍历的过程中,还要把前面的一个节点保存起来
else
{
struct node_info *pre = info->first;
struct node_info *cur = pre->next;
while(cur!=NULL&&cur!=node)
{
pre = pre->next;
cur = cur->next;
}
if(cur==NULL)
return -1; // the node to delete is not in the list
pre->next = cur->next;//delete
free(cur);
return 0;
} }

假设有个程序员很粗心,让最后一个节点的next指针指向了链表中的某一个节点,你能检查出来吗?

1----2----3----4----5----6----7----8----9

|                           |

|----------------------|

比如这个图,1是第一个,9的后面是5,构成了一个环。

思路是这样的:假设2个人,一个人每次走1步,另一个每次走2步。同时出发,如果有环存在,那么这两个人肯定会相遇的!因为两个人都要在圈里面绕,步长差1,那么快的那个肯定会追赶慢的那个,总会追上的!------此思路我们称为“追赶法”!

int slist_is_dead_loop(struct slist_info *info)
{
assert(info != NULL);
assert(!slist_is_empty(info)); assert(info->first->next!=NULL);//节点数不少于两个
struct node_info *slow = info->first;
struct node_info *fast = info->first; while (fast!= NULL && fast->next != NULL) { //che 2014.4.28 fast = fast->next->next;
slow = slow->next;
if (fast == slow) {
break;//相遇
} } if (fast != slow) {
return 0; //无死环
}
//此时相遇。怎么求环的长度呢?
//fast固定,每次移动1步slow,再次相遇的时候,移动的步数就是环的长度
int step = 1;
slow = slow->next; while(fast!=slow)
{
slow = slow->next;
++step;
}
printf("the circle = %d\n",step); //怎么求环前面那段链子的长度?

O----------------------------------------E-----------------------A-------

|------------------------------- |

如图,假设E点是环的起点,设OE长为x,环的长度是L.

我们安排一个场景,甲乙两个人,乙先出发,走到A点时候,甲出发了,两个人的速度是一样的,在E点的时候,两人相遇了!这时候甲走的步数就是链子的长度!问题是A点是哪里呢?

我们可以列出等式   x+L = 乙先走的(OA)+乙后走的(也就是甲走的x)

所以,OA=L

也就是说,先让乙走L步,然后两个人都走,相遇的时候,甲走的就是所求,接着上面的代码

//设环的长度为L,让两个人都回到起点,先让P2向前走L步。
//然后p1,p2每次往前走一步,当他们相遇的时候,p1移动的步数就是所求
fast = slow = info->first;
while(step--)
fast = fast->next; //P2向前走L步 step = 0;
while(fast!=slow)
{
slow = slow->next;
fast = fast->next;
++step;
}
printf("the line = %d\n",step);//链子的长度
return 1; //有死环
}

关于测试代码,下次再说。

C语言实现通用链表初步(二)的更多相关文章

  1. C语言实现通用链表初步(一)

    注意:本文讨论的是无头单向非循环链表. 假设不采用Linux内核链表的思路,怎样用C语言实现通用链表呢? 一种常用的做法是: typedef int element_t; struct node_in ...

  2. C语言实现通用链表初步(四)----双向链表

    在前面的文章中,我们讨论了如何实现通用类型的链表,方法是用void *类型的指针,指向数据.那么还有其他的方法吗(不考虑内核链表)? 答案是肯定的.用零长数组也可以实现. struct node_in ...

  3. C语言实现通用链表初步(三)----单元测试

    前两节,我们已经完成了链表的一些操作,快来测试一下吧. 这里使用的单元测试工具名字叫"check". START_TEST(my_slist_1) { struct student ...

  4. C/C++语言实现单链表(带头结点)

    彻底理解链表中为何使用二级指针或者一级指针的引用 数据结构之链表-链表实现及常用操作(C++篇) C语言实现单链表,主要功能为空链表创建,链表初始化(头插法),链表元素读取,按位置插入,(有序链表)按 ...

  5. [LeetCode] Convert Sorted List to Binary Search Tree 将有序链表转为二叉搜索树

    Given a singly linked list where elements are sorted in ascending order, convert it to a height bala ...

  6. [LeetCode] Reverse Linked List II 倒置链表之二

    Reverse a linked list from position m to n. Do it in-place and in one-pass. For example:Given 1-> ...

  7. C语言细节——献给初学者(二)

    C语言细节——献给初学者(二) 主题  循环运用+选择判断 C语言循环有for和while/do...while: 选择判断有:if...else和switch...case 在循环中需要注意搭配br ...

  8. C语言实现单链表-03版

    在C语言实现单链表-02版中我们只是简单的更新一下链表的组织方式: 它没有更多的更新功能,因此我们这个版本将要完成如下功能: Problem 1,搜索相关节点: 2,前插节点: 3,后追加节点: 4, ...

  9. C语言实现单链表-02版

    我们在C语言实现单链表-01版中实现的链表非常简单: 但是它对于理解单链表是非常有帮助的,至少我就是这样认为的: 简单的不能再简单的东西没那么实用,所以我们接下来要大规模的修改啦: Problem 1 ...

随机推荐

  1. win8使用every'thing无法显示搜索结果的解决方法

    关键词: win8,everything,无搜索结果 进入everything ,tools->option右下角有个 restore defaults 如果安全软件阻拦,点击  允许 就行了, ...

  2. C/C++单向链表

    由于时间仓促,作者并没有进行任何的检查,总之徒手165行,调试无BUG,基本功能的实现并无大问题,可能有些细节考虑不周(这也是C/C++的诟病,小车不倒只管前推),还忘见谅. 代码是在C++环境编写, ...

  3. 如何使用Visual Studio 2010在数据库中生成随机测试数据

    测试在项目中是很重要的一个环节,在Visual Studio 2010中,在测试方面已经有很好的支持了,比如有单元测试,负载测试等等.在数据测试的方面,Visual Studio 2010,还支持对数 ...

  4. 怎样创建XML文档

    在程序中,我们怎样创建一个XML文档.下面演示中,Insus.NET在程序创建一个和http://www.cnblogs.com/insus/p/3274220.html 一模一样的XML文档. 可以 ...

  5. 算法训练 K好数 (DP)

    问题描述 如果一个自然数N的K进制表示中任意的相邻的两位都不是相邻的数字,那么我们就说这个数是K好数.求L位K进制数中K好数的数目.例如K = 4,L = 2的时候,所有K好数为11.13.20.22 ...

  6. hpp文件简介

    Boost库文件采用的.hpp的后缀,而不是分成两个文件,也就是”.h+.cpp”,之所以这样做是有理由的,首先就是与普通的C/C++头文件区分,另外一个原因就是使Boost库不需要预先编译,直接引用 ...

  7. 转载黑客是如何黑到你手机的?绝对涨姿势,一位黑客的Wi-Fi入侵实录!

        声明:这是一虚构的故事,因此对图片均进行了模糊化处理.内容整理自网络! 故事的主人公小黑是一名从事IT相关工作的技术宅男.五一长假来临,宅在家中的他相当无聊,打开手机上的Wi-Fi模块,发现附 ...

  8. C语言数据结构-栈的实现-初始化、销毁、长度、取栈顶元素、查找、入栈、出栈、显示操作

    1.数据结构-栈的实现-C语言 #define MAXSIZE 100 //栈的存储结构 typedef struct { int* base; //栈底指针 int* top; //栈顶指针 int ...

  9. 微信Dat文件解码

    最近在整理磁盘文件,因为经过一段时间的蹂躏后,磁盘实在是太多东西了,不整理一下,简直对不住我的SSD好嘛.偶然发现磁盘中某公司的文件夹占用空间简直不能再大,那可是我的C盘啊,合计才119GB的SSD空 ...

  10. zabbix告警

    邮件告警分为两大步: 第一步:配置(配置又分为三小步) 发送邮件的用户 创建用户(添加上告警媒介) 给用户添加权限(在所有组里添加) 最后显示有读写权限才算成功!!! 告警媒介类型 创建媒介类型!一般 ...