设置两个指针,让其中一个先前移k-1步,然后两个指针同时往前移动。直到先行的指针指到null,另一个就指到k。
/** * 找出单链表中倒数第k个元素 * @param head * @param k * @return */ public Node findElem(Node head, int k){ if (k<1) return null; Node p1 =head; Node p2 =head; for (int i=0;i<k-1&&p1!=null;i++) p1=p1.next; if (p1==null){ System.out.println("k不合法!"); return null; } while (p1.next!=null){ p1=p1.next; p2=p2.next; } return p2; }用递归的方法实现的
/** * 从尾到头输出单链表 * @param pListHead */ public void printListReversely(Node pListHead){ if (pListHead != null){ printListReversely(pListHead.next); System.out.println(pListHead.data); } }设置两个指针从头遍历,一个快指针走两步,一个慢指针走一步。快指针走到头,慢指针恰好到中间节点
/** * 寻找单链表的中间节点 * @param head * @return */ public Node searchMid(Node head){ Node p =head; Node q =head; while(p!= null && p.next!=null &&p.next.next!=null){ p = p.next.next; q = q.next; } return q; }设置两个指针,fast快指针,走两步,slow慢指针,走一步。比较两个指针的值是否相等。当fast与slow的值相同,测试循环链表
/** * 检测一个链表是否有环 * @param head * @return */ public boolean isLoop(Node head){ Node fast = head; Node slow = head; if (fast==null){ return false; } while(fast!=null && fast.next!=null){ fast = fast.next.next; slow = slow.next; if (fast.data==slow.data){ return true; } } return !(fast==null || fast.next==null); }如何找到环的入口点呢? 如果单链表有环,按照上述思路,当走的快的指针fast与走的慢的指针slow相遇时,slow指针肯定没有遍历完链表,而fast指针已经在环内循环了n圈 ( n > = 1)。假设slow指针走了 s 步,则fast 指针走了 2s 步 (fast步数还等于 s 加上在环内多转的 n 圈),设环长为 r ,满足如下关系表达式: 2s = s + nr; s = nr; 设整个链表长L,入口环与相遇点距离 x ,起点到环入口点的距离为a,则满足如下关系表达式: a + s = nr; a + s = (n - 1)r + r = (n - 1)r + L - a ; a = (n - 1)r + (L - a - x); (L - a - x)为相遇点到环入口点的距离,从链表头到环入口点等于(n - 1)循环内环+ 相遇点到环入口点,于是在链表头与相遇点分别设置一个指针,每一次各走一步,两个指针必定相遇,且遇到的第一个点为环入口点。 具体代码如下:
/** * 寻找循环链表的环入口 * @return */ public Node findLoopPort(Node head){ Node slow = head; Node fast = head; while(fast!=null && fast.next!=null){ slow = slow.next; fast = fast.next.next; if (slow==fast) break; } if (fast == null && fast.next==null){ return null; } slow = head; while (slow!=fast){ slow = slow.next; fast = fast.next; } return slow; }如果两个链表相交,那么他们的尾结点一定相同
/** * 判断两个链表是否相交 * @param h1 * @param h2 * @return */ public boolean isIntersect(Node h1,Node h2){ if (h1==null || h2==null){ return false; } Node tail1 =h1; while (tail1!=null){ tail1 = tail1.next; } Node tail2 = h2; while (tail2!=null){ tail2 = tail2.next; } return tail1==tail2; }如何找出第一个相交的点? 首先分别计算两个链表的长度。长的链表先遍历(len1 - len2)步,使剩下的长度相等,然后两个链表一起遍历。每一步都比较值是否相等。如果相等,就返回节点。
public static Node getFirstMeetNode(Node h1,Node h2){ if (h1==null||h2==null){ return null; } Node tail1 = h1; int len1=1; while (tail1!=null){ tail1=tail1.next; len1++; } Node tail2 = h2; int len2=1; while (tail2.next!=null){ tail2=tail2.next; len2++; } //两链表不相交 if (tail1!=tail2){ return null; } Node t1 = h1; Node t2 = h2; //找出较长的链表,先遍历 if (len1>len2){ int d =len1-len2; while (d!=0){ t1 = t1.next; d--; } }else { int d =len2 - len1; while (d!=0){ t2 = t2.next; d--; } } while (t1!=t2){ t1=t1.next; t2=t2.next; } return t1; }