【数据结构】链表的一些问题
2017-12-31 12:35
411 查看
【题 1】找到链表的倒数第n个节点
【分析】有效方法为使用2个指针node和temp。首先,2个指针都指向表头结点,仅当temp(沿链表)进行了(n-1)次移动,node开始一起移动,直至temp到达尾节点结束,此时node指针指向的就是倒数第n个节点
【题 2】如何判定给定链表是不是环
【分析】Floyd环判定算法。该方法使用2个在链表中不同移动速度的指针。一旦他们进入环就会相遇。
【题 3】判定给定链表是否是环,如果环存在,找到环的起点
【分析】在判断是环后,令slow = head,再让两个指针每次移动一个节点,相遇时即为环的起点。
设环的起点是链表的第(m+1)个节点,环有n个节点,相遇时在环的第c个节点,slow移动了x步,fast移动了y步
x = kn + m + c; y = 2x = 2kn + 2m +2c; y - x = kn + m + c = tn(相差的步数应该是n的整数倍);
所以m + c = pn,即m = pn - c
所以slow从head开始移动m + 1步时指向的是环的起点,
fast已经是环的第c个点了,再移动(m+1)步,即(c + pn - c +1) 步,指向节点为
(pn +1) mod n = 1即环的首节点
【题 4】如果给定链表存在环,求环的长度
【分析】当在环中slow和fast相遇时,令slow不变,fast继续移动,步长变为1,记下移动的次数k,当slow与fast再次相遇时,k即为环的长度
【题 5】逆置单向链表
【题 6】假设2个单向链表在某个节点相交后,成为一个单向链表。两个链表的表头节点是已知的,但是相交的节点未知。也就是说它们相交之前各自的节点数是未知的,并且两个链表的节点数也可能不同。假设链表List1和链表List2在相交前的节点数分别为m和n,那么m和n的大小是不确定的。请设计算法找到两个链表的合并点。
【分析】获取2个链表长度,计算处长度差d,从较长链表开始移动d步,然后大家一起以相同速度移动,当指针相等时即为合并点
【题 7】如何查找链表的中间结点
【分析】使用2个指针,一个步长2,一个步长1
方法一
方法二
【题 8】从表尾开始输出链表
【分析】运用递归
【题 9】约瑟夫环:N个人想选出一个领头人,他们排成一个环,沿着环每数到M个人就排除该人,并从下一个人开始重新数。请找出最后的人。
【分析】看做是有N个节点的循环链表,每个人给个编号(1~N)
【分析】有效方法为使用2个指针node和temp。首先,2个指针都指向表头结点,仅当temp(沿链表)进行了(n-1)次移动,node开始一起移动,直至temp到达尾节点结束,此时node指针指向的就是倒数第n个节点
public ListNode getNodeFromEnd(int n){ if(n <= 0 && n > size){ throw new RuntimeException("超出链表范围!"); } ListNode node = head, temp = head; for(int count = 1; count < n; count++){ temp = temp.getNext(); } while(temp.getNext() != null){ temp = temp.getNext(); node = node.getNext(); } return node; }
【题 2】如何判定给定链表是不是环
【分析】Floyd环判定算法。该方法使用2个在链表中不同移动速度的指针。一旦他们进入环就会相遇。
public boolean isLoop(){ ListNode fast = head, slow = head; while(fast.getNext() != null && fast.getNext().getNext() != null){ fast = fast.getNext().getNext(); slow = slow.getNext(); if(fast == slow){ return true; } } return false; }
【题 3】判定给定链表是否是环,如果环存在,找到环的起点
【分析】在判断是环后,令slow = head,再让两个指针每次移动一个节点,相遇时即为环的起点。
设环的起点是链表的第(m+1)个节点,环有n个节点,相遇时在环的第c个节点,slow移动了x步,fast移动了y步
x = kn + m + c; y = 2x = 2kn + 2m +2c; y - x = kn + m + c = tn(相差的步数应该是n的整数倍);
所以m + c = pn,即m = pn - c
所以slow从head开始移动m + 1步时指向的是环的起点,
fast已经是环的第c个点了,再移动(m+1)步,即(c + pn - c +1) 步,指向节点为
(pn +1) mod n = 1即环的首节点
public ListNode findLoopBeginNode(){ boolean isLoop = false; ListNode fast = head, slow = head; while(fast.getNext() != null && fast.getNext().getNext() != null){ fast = fast.getNext().getNext(); slow = slow.getNext(); if(fast == slow){ isFloyd = true; break; } } if(isLoop){ slow = head; while(slow != fast){ slow = slow.getNext(); fast = fast.getNext(); } return slow; } return null; }
【题 4】如果给定链表存在环,求环的长度
【分析】当在环中slow和fast相遇时,令slow不变,fast继续移动,步长变为1,记下移动的次数k,当slow与fast再次相遇时,k即为环的长度
public int loopLength(){ boolean isLoop = false; ListNode fast = head, slow = head; while(fast.getNext() != null && fast.getNext().getNext() != null){ fast = fast.getNext().getNext(); slow = slow.getNext(); if(fast == slow){ isFloyd = true; break; } } if(isLoop){ fast = fast.getNext(); int k = 1; while( slow != fast){ fast = fast.getNext(); ++k; } return k; } return 0; }
【题 5】逆置单向链表
public void reverse(){ ListNode temp = null, nextNode = head.getNext(), reverseNode = null; while(nextNode != null){ reverseNode = nextNode; reverseNode.setNext(temp); temp = reverseNode; nextNode = nextNode.getNext(); } head.setNext(reverseNode); }
【题 6】假设2个单向链表在某个节点相交后,成为一个单向链表。两个链表的表头节点是已知的,但是相交的节点未知。也就是说它们相交之前各自的节点数是未知的,并且两个链表的节点数也可能不同。假设链表List1和链表List2在相交前的节点数分别为m和n,那么m和n的大小是不确定的。请设计算法找到两个链表的合并点。
【分析】获取2个链表长度,计算处长度差d,从较长链表开始移动d步,然后大家一起以相同速度移动,当指针相等时即为合并点
public ListNode findIntersectintNode(SList list1, SList list2){ //有些可能出现的NullPointerException这里没主动判断,只是用来说明算法 ListNode head1 = list1.getHead(), head2 = list2.getHead(); ListNode temp1 = head1.getNext(); temp2 = head2.getNext(); int length1 = 0, length2 = 0, d = 0; while(temp1 != null){ length1++; temp = temp.getNext(); } while(temp2 != null){ length2++; temp = temp.getNext(); } if(length1 > length2){ temp1 = head1; temp2 = head2; d = length1 - length2; }else{ temp1 = head2; temp2 = head1; d = length2 - length1; } for(int i = 0; i < d; i++){ temp1 = temp1.getNext(); } while(temp1 != null && temp2 != null){ temp1 = temp1.getNext(); temp2 = temp2.getNext(); if(temp1 == temp2){ return temp1; } } return null; }
【题 7】如何查找链表的中间结点
【分析】使用2个指针,一个步长2,一个步长1
方法一
public ListNode midNode(){ ListNode fast = head, slow = head; int n =0; while(fast.getNext() != null){ if(n == 0){ fast = fast.getNext(); n = 1; }else if(n == 1){ fast = fast.getNext(); slow = slow.getNext(); n = 0; } } return slow.getNext(); }
方法二
public ListNode midNode(){ ListNode fast = head, slow = head; while(fast.getNext() != null && fast.getNext().getNext() != null){ fast = fast.getNext().getNext(); slow = slow.getNext(); } return slow.getNext(); }
【题 8】从表尾开始输出链表
【分析】运用递归
public void printFromEnd(ListNode head){ if(isEmpty){ return; } printFromEnd(head.getNext()); System.out.println(head.getData()); }
【题 9】约瑟夫环:N个人想选出一个领头人,他们排成一个环,沿着环每数到M个人就排除该人,并从下一个人开始重新数。请找出最后的人。
【分析】看做是有N个节点的循环链表,每个人给个编号(1~N)
public int getLeader(int N,int M){ //建立循环链表 CList list = new CList(); ListNode p = list.getHead(); ListNode q; for(int i = 1; i <= N; i++){ q = new ListNode(); q.setData(i); p.setNext(p); p = p.getNext(); } p.setNext(list.getHead().getNext()); //设置尾节点指向首节点 //现在p指向的是尾节点 for( init count = N; count > 1; count--){ for(int k = 1; k < M; k++){ p = p.getNext(); } p.setNext(p.getNext().getNext()); //从链表中删除淘汰选手 } return list.getHead().getNext().getData(); }
相关文章推荐
- 数据结构链表的一些的问题
- 数据结构链表的一些操作!
- C语言数据结构之单向链表(已经调试可以实现相应的功能了,可是还是有几个问题现在还是不大理解,希望大家能够一起探讨)
- 数据结构 -链表反转问题
- 单链表基本操作以及一些常见的面试问题
- 【数据结构 链表的应用】一元多项式相加及相乘 和对问题的分析
- 由链表而想到的一些问题[讨论]
- iOS 单链表算法的一些问题
- ytu 2231: 交集问题(线性表)(数据结构,链表练习)
- 算法与数据结构面试题(7)-链表“香蕉”问题
- 关于遇到过链表问题的一些总结
- 关于数据结构中单链表一些操作
- 【数据结构】c语言链表实现报数问题
- 数据结构中关于链表的一个简单问题
- 数据结构 循环链表之约瑟夫问题
- 链表中的一些问题——快慢指针
- 学习数据结构中一些C语言问题集锦2
- 数据结构(4)--循环链表的应用之约瑟夫环问题以及线性表总结之顺序表与链表的比较
- 数据结构的一些问题
- 【数据结构 _双向链表_List_0960】双向链表的操作问题