您的位置:首页 > 理论基础 > 数据结构算法

【数据结构】链表的一些问题

2017-12-31 12:35 411 查看
【题 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();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: