求有环单链表中的环长、环起点、链表长

1.判断单链表是否有环

  使用两个slow, fast指针从头开始扫描链表。指针slow 每次走1步,指针fast每次走2步。如果存在环,则指针slow、fast会相遇;如果不存在环,指针fast遇到NULL退出。

  就是所谓的追击相遇问题:

    

2.求有环单链表的环长

   在环上相遇后,记录第一次相遇点为Pos,之后指针slow继续每次走1步,fast每次走2步。在下次相遇的时候fast比slow正好又多走了一圈,也就是多走的距离等于环长。

  设从第一次相遇到第二次相遇,设slow走了len步,则fast走了2*len步,相遇时多走了一圈:

    环长=2*len-len。

3.求有环单链表的环连接点位置

  第一次碰撞点Pos到连接点Join的距离=头指针到连接点Join的距离,因此,分别从第一次碰撞点Pos、头指针head开始走,相遇的那个点就是连接点。

     

  在环上相遇后,记录第一次相遇点为Pos,连接点为Join,假设头结点到连接点的长度为LenA,连接点到第一次相遇点的长度为x,环长为R

    第一次相遇时,slow走的长度 S = LenA + x;

    第一次相遇时,fast走的长度 2S = LenA + n*x;

    所以可以知道,LenA + x =  n*R;  LenA = n*R -x;

4.求有环单链表的链表长

   上述2中求出了环的长度;3中求出了连接点的位置,就可以求出头结点到连接点的长度。两者相加就是链表的长度。

 

编程实现:

  下面是代码中的例子:

  

  具体代码如下:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 typedef struct node{
  4     int value;
  5     struct node *next;
  6 }LinkNode,*Linklist;
  7
  8 /// 创建链表(链表长度,环节点起始位置)
  9 Linklist createList(){
 10     Linklist head = NULL;
 11     LinkNode *preNode = head;
 12     LinkNode *FifthNode = NULL;
 13     for(int i=0;i<6;i++){
 14         LinkNode *tt = (LinkNode*)malloc(sizeof(LinkNode));
 15         tt->value = i;
 16         tt->next = NULL;
 17         if(preNode == NULL){
 18             head = tt;
 19             preNode = head;
 20         }
 21         else{
 22             preNode->next =tt;
 23             preNode = tt;
 24         }
 25
 26         if(i == 3)
 27             FifthNode = tt;
 28     }
 29     preNode->next = FifthNode;
 30     return head;
 31 }
 32
 33 ///判断链表是否有环
 34 LinkNode* judgeRing(Linklist list){
 35     LinkNode *fast = list;
 36     LinkNode *slow = list;
 37
 38     if(list == NULL)
 39         return NULL;
 40
 41     while(true){
 42         if(slow->next != NULL && fast->next != NULL && fast->next->next != NULL){
 43             slow = slow->next;
 44             fast = fast->next->next;
 45         }
 46         else
 47             return NULL;
 48
 49         if(fast == slow)
 50             return fast;
 51     }
 52 }
 53
 54 ///获取链表环长
 55 int getRingLength(LinkNode *ringMeetNode){
 56     int RingLength=0;
 57     LinkNode *fast = ringMeetNode;
 58     LinkNode *slow = ringMeetNode;
 59     for(;;){
 60         fast = fast->next->next;
 61         slow = slow->next;
 62         RingLength++;
 63         if(fast == slow)
 64             break;
 65     }
 66     return RingLength;
 67 }
 68
 69 ///获取链表头到环连接点的长度
 70 int getLenA(Linklist list,LinkNode *ringMeetNode){
 71     int lenA=0;
 72     LinkNode *fast = list;
 73     LinkNode *slow = ringMeetNode;
 74     for(;;){
 75         fast = fast->next;
 76         slow = slow->next;
 77         lenA++;
 78         if(fast == slow)
 79             break;
 80     }
 81     return lenA;
 82 }
 83
 84 ///环起始点
 85 ///如果有环, 释放空空间时需要注意.
 86 LinkNode* RingStart(Linklist list, int lenA){
 87     if (!list || lenA <= 0){
 88         return NULL;
 89     }
 90
 91     int i = 0;
 92     LinkNode* tmp = list;
 93     for ( ; i < lenA; ++i){
 94         if (tmp != NULL){
 95             tmp = tmp->next;
 96         }
 97     }
 98
 99     return (i == lenA)? tmp : NULL;
100 }
101
102 ///释放空间
103 int freeMalloc(Linklist list, LinkNode* ringstart){
104     bool is_ringstart_free = false; //环起始点只能被释放空间一次
105     LinkNode *nextnode = NULL;
106
107     while(list != NULL){
108         nextnode = list->next;
109         if (list == ringstart){ //如果是环起始点
110             if (is_ringstart_free)
111                 break;  //如果第二次遇到环起始点addr, 表示已经释放完成
112             else
113                 is_ringstart_free = true;   //记录已经释放一次
114         }
115         free(list);
116         list = nextnode;
117     }
118
119     return 0;
120 }
121
122 int main(){
123     Linklist list = NULL;
124     LinkNode *ringMeetNode  = NULL;
125     LinkNode *ringStartNode = NULL;
126
127     int LenA       = 0;
128     int RingLength = 0;
129
130     list = createList();
131     ringMeetNode = judgeRing(list); //快慢指针相遇点
132
133     if(ringMeetNode == NULL)
134         printf("No Ring\n");
135     else{
136         printf("Have Ring\n");
137         RingLength = getRingLength(ringMeetNode);   //环长
138         LenA = getLenA(list,ringMeetNode);
139
140         printf("RingLength:%d\n", RingLength);
141         printf("LenA:%d\n", LenA);
142         printf("listLength=%d\n", RingLength+LenA);
143     }
144
145     ringStartNode = RingStart(list, LenA);  //获取环起始点
146     freeMalloc(list, ringStartNode);    //释放环节点, 有环时需要注意. 采纳5楼建议
147     return 0;
148 }

View Code

  执行结果:

本文网址:http://www.cnblogs.com/xudong-bupt/p/3667729.html

参考网址:http://blog.sina.com.cn/s/blog_725dd1010100tqwp.html

时间: 2024-07-28 15:25:59

求有环单链表中的环长、环起点、链表长的相关文章

亲们,我把环信Demo中的代码移植到我的项目中,别的都调试成功了,就删除本地聊天记录出错,为什么,急求

问题描述 亲们,我把环信Demo中的代码移植到我的项目中,别的都调试成功了,就删除本地聊天记录出错:android.database.sqlite.SQLiteException: no such table: new_friends_msgs (code 1): , while compiling: DELETE FROM new_friends_msgs WHERE username = ? 解决方案 报错信息显示没有这个表, 这张表是代码层创建的,sdk代码中不负责创建的.看下com.ea

防御性编程习惯:求出链表中倒数第 m 个结点的值及其思想的总结

防御性编程习惯 程序员在编写代码的时候,预料有可能出现问题的地方或者点,然后为这些隐患提前制定预防方案或者措施,比如数据库发生异常之后的回滚,打开某些资源之前,判断图片是否存在,网络断开之后的重连次数或者是否连接备用网络,除法运算中的除数问题,函数或者类在接受数据的时候的过滤情况,比如如果输入一个指针参数,是否需要判断是不是空指针?输入一个字符串参数,是否需要判断字符串空否--总的来说就是防止出现不可预见的事情,设计出鲁棒性的代码. 看下面的例子 输入一个链表,输出链表中倒数第 m 个结点额内容

单链表中main函数出现死循环

问题描述 单链表中main函数出现死循环 int main() { int choice;//选项 int n;//结点个数 int i;//位置 ElemType e; LNode *L; cout<<"选项:n1.创建n2.插入n3.删除n0.退出n请选择:"< cin>>choice; while(1) { switch(choice) { case 1: InitList_L(L);//单链表的初始化 cout<<"请输入结点

WPS演示中生成12色相环的方法

  WPS演示中生成12色相环的方法 1.打开WPS演示,点击插入--图表,会在WPS表格中生成一个带图表的表格. 2.鼠标右键单击图表空白处,选择图表类型. 3.然后选择圆环图,第一个,确定. 4.选中B3:B4,右键,选择删除整行. 5.这时圆环图只有一种颜色了,双击某一部分圆环,在弹出的界面设置颜色. 6.把每一部分设置好颜色,按照12色相环色顺序设置,最终得到如下图所示的效果图.

跳转路径-急求解决,jsp页面中循环生成的form表单,action路径错误

问题描述 急求解决,jsp页面中循环生成的form表单,action路径错误 在jsp页面中用循环生成的form表单,为什么action不是想要的呢,代码贴在下面了 reply=(Map)request.getAttribute("REPLY"); while(rsComment.next()) { // 评论编号 String CId = rsComment.getString("CId"); // 评论人 String name=rsComment.getStr

单链表中查找结点p并删除结点p

问题描述 单链表中查找结点p并删除结点p pointer *p*q=NULL; p=find(headi+1); cout<data< q->next=p; q->next=p->next; delete p; } 网上的实现方法都是删除p的后继结点,我想直接删除p,按照我的想法上述语句应该是正确的,但是执行时候在q->next=p出显示又断点,怎么破 大神救我 解决方案 你应该从头结点开始遍历比如说头结点为 L:假设你要删的结点为p设置一个 q=L;m=q->n

python实现:删除链表中等于给定值val的所有节点.求代码学习

问题描述 python实现:删除链表中等于给定值val的所有节点.求代码学习 例如:给出链表 1->2->3->3->4->5->3, 和 val = 3, 需要返回删除3之后的链表:1->2->4->5. 解决方案 python怎么考虑链表,是用类来实现链表节点吗? 如果不是,就简单了. def remove(arr): #arr=[1,2,3,3,4,5,3] arr_len = len(arr) for i in range(0,arr_len)

c语言-求一个关于C语言中有关文件和链表的一个程序

问题描述 求一个关于C语言中有关文件和链表的一个程序 我们老师布置了一道题:有A和B两个文件夹,每个文件夹下面都有若干子目录.但是 不知道目录里面文件的类型和具体的文件数目.现在要创建一个C文件夹,对C文件夹 的要求是:(1)C文件夹下面子目录的文件名和文件长度是A的,打开的内容是B的( 打开之后只要内容是B的,不要求内容完整与否).(2)通过键入命令或是其他方式 C文件夹可以直接恢复到B文件夹.要求使用链表完成. 我们老师只把题目说了这些,他说对A.B文件夹的定义让我们自己讨论吧.能实现他所

安卓环信集成中添加好友不要验证时遇到问题

问题描述 在安卓的环信集成中,添加好友时我不想验证,直接添加成功.但是遇到问题了,我这样修改了之后再后台中看到依然不是好友.要等到对方登陆环信之后我再登陆时才成添加成好友.我现在想再请求添加成为好友之后立即变成好友,请问该怎么修改呢 解决方案 EMChatManager.getInstance().getChatOptions().setAcceptInvitationAlways(false);设置false就可以了解决方案二:因为环信的sdk那个不需要验证添加好友设置,最终还是通过sdk自己