轉自網上的 關於鏈表的基本操作

package 鏈表;

import java.util.HashMap;
import java.util.Scanner;
import java.util.Stack;

/**
 * 
 * @author kerryfish
 * 關於java中鏈表的操作
 * 1. 求單鏈表中結點的個數: getListLength 
 * 2. 將單鏈表反轉: reverseList(遍歷),reverseListRec(遞歸) 
 * 3. 查找單鏈表中的倒數第K個結點(k > 0): reGetKthNode 
 * 4. 查找單鏈表的中間結點: getMiddleNode 
 * 5. 從尾到頭打印單鏈表: reversePrintListStack,reversePrintListRec(遞歸) 
 * 6. 已知兩個單鏈表pHead1 和pHead2 各自有序,把它們合併成一個鏈表依然有序: mergeSortedList, mergeSortedListRec 
 * 7. 對單鏈表進行排序,listSort(歸併),insertionSortList(插入)
 * 8. 判斷一個單鏈表中是否有環: hasCycle 
 * 9. 判斷兩個單鏈表是否相交: isIntersect 
 * 10. 已知一個單鏈表中存在環,求進入環中的第一個節點: getFirstNodeInCycle, getFirstNodeInCycleHashMap 
 * 11. 給出一單鏈表頭指針head和一節點指針delete,O(1)時間複雜度刪除節點delete: deleteNode
 */
public class LinkedListSummary {
    /**
     * @param args
     * 
     */
    public static class Node{
        int value;
        Node next;
        public Node(int n){
            this.value=n;
            this.next=null;
        }
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner in=new Scanner(System.in);
        Node head=null;
        if(in.hasNextInt()){
            head=new Node(in.nextInt());
        }
        Node temp=head;
        while(in.hasNextInt()){
            temp.next=new Node(in.nextInt());
            temp=temp.next;
        }
        in.close();
//      Node n = head;    
//      Node pre = null;     頭插法
//      Node next = null;
//      while(n!= null){
//          next = n.next;
//          n.next=pre;
//          pre=n;
//          n=next;
//      }
//      while(pre !=null){
//          System.out.println(pre.value);
//          pre = pre.next;
//      }
        //int len=getListLength(head);
        //Node reHead=reverseList(head);
        //reHead=reverseListRec(reHead);
        //Node node_k=reGetKthNode(head,3);
        //Node mid=getMiddleNode(head);
        //reversePrintListRec(head);
        //reversePrintListStack(head);
        //Node mergeHead=mergeSortedList(head,null);
        //Node sortHead=listSort(head);

    }

    //求單鏈表中結點的個數: getListLength 
    public static int getListLength(Node head){
        int len=0;
        while(head!=null){
            len++;
            head=head.next;
        }
        return len;
    }
    //將單鏈表反轉,循環
    public static Node reverseList(Node head){
        if(head==null||head.next==null)return head;
        Node pre=null;
        Node nex=null;
        while(head!=null){
            nex=head.next;
            head.next=pre;
            pre=head;
            head=nex;
        }
        return pre;
    }
    //將單鏈表反轉,遞歸
    public static Node reverseListRec(Node head){
        if(head==null||head.next==null)return head;
        Node reHead=reverseListRec(head.next);
        head.next.next=head;
        head.next=null;
        return reHead;
    }
    //查找單鏈表中的倒數第K個結點(k > 0)
    public static Node reGetKthNode(Node head,int k){
        if(head==null)return head;
        int len=getListLength(head);
        if(k>len)return null;
        Node target=head;
        Node nexk=head;
        for(int i=0;i<k;i++){
            nexk=nexk.next;
        }
        while(nexk!=null){
            target=target.next;
            nexk=nexk.next;
        }
        return target;
    }
    //查找單鏈表的中間結點 
    public static Node getMiddleNode(Node head){
        if(head==null||head.next==null)return head;
        Node target=head;
        Node temp=head;
        while(temp!=null&&temp.next!=null){
            target=target.next;
            temp=temp.next.next;
        }
        return target;
    }
    //從尾到頭打印單鏈表,遞歸
    public static void reversePrintListRec(Node head){
        if(head==null)return;
        else{
            reversePrintListRec(head.next);
            System.out.println(head.value);
        }
    }
    //從尾到頭打印單鏈表,棧
    public static void reversePrintListStack(Node head){
        Stack<Node> s=new Stack<Node>();
        while(head!=null){
            s.push(head);
            head=head.next;
        }
        while(!s.isEmpty()){
            System.out.println(s.pop().value);
        }
    }
    //合併兩個有序的單鏈表head1和head2,循環
    public static Node mergeSortedList(Node head1,Node head2){
        if(head1==null)return head2;
        if(head2==null)return head1;
        Node target=null;
        if(head1.value>head2.value){
            target=head2;
            head2=head2.next;
        }
        else{
            target=head1;
            head1=head1.next;
        }
        target.next=null;
        Node mergeHead=target;
        while(head1!=null && head2!=null){
            if(head1.value>head2.value){
                target.next=head2;
                head2=head2.next;
            }
            else{
                target.next=head1;
                head1=head1.next;
            }
            target=target.next;
            target.next=null;
        }
        if(head1==null)target.next=head2;
        else target.next=head1;
        return mergeHead;
    }
    //合併兩個有序的單鏈表head1和head2,遞歸
    public static Node mergeSortedListRec(Node head1,Node head2){
        if(head1==null)return head2;
        if(head2==null)return head1;
        if(head1.value>head2.value){
            head2.next=mergeSortedListRec(head2.next,head1);
            return head2;
        }
        else{
            head1.next=mergeSortedListRec(head1.next,head2);
            return head1;
        }
    }
    //對單鏈表進行排序,歸併排序,在排序裏面不建議選用遞歸的合併有序鏈表算法,如果鏈表長度較長,很容易出現棧溢出
    public static Node listSort(Node head){
        Node nex=null;
        if(head==null||head.next==null)return head;
        else if(head.next.next==null){
            nex=head.next;
            head.next=null;
        }
        else{
            Node mid=getMiddleNode(head);
            nex=mid.next;
            mid.next=null;
        }
        return mergeSortedList(listSort(head),listSort(nex));//合併兩個有序鏈表,不建議遞歸
    }
    //對單鏈表進行排序,插入排序
    public Node insertionSortList(Node head) {
        if(head==null||head.next==null)return head;
        Node pnex=head.next;
        Node pnex_nex=null;
        head.next=null;
        while(pnex!=null){
            pnex_nex=pnex.next;
            Node temp=head;
            Node temp_pre=null;
            while(temp!=null){
                if(temp.value>pnex.value)break;
                temp_pre=temp;
                temp=temp.next;
            }
            if(temp_pre==null){
                head=pnex;
                pnex.next=temp;
            }
            else{
                temp_pre.next=pnex;
                pnex.next=temp;
            }
            pnex=pnex_nex;
        }
        return head;
    }
    //判斷一個單鏈表中是否有環,快慢指針
    public static boolean hasCycle(Node head){
        boolean flag=false;
        Node p1=head;
        Node p2=head;
        while(p1!=null&&p2!=null){
            p1=p1.next;
            p2=p2.next.next;
            if(p2==p1){
                flag=true;
                break;
            }
        }
        return flag;
    }
    //判斷兩個單鏈表是否相交,如果相交返回第一個節點,否則返回null
    //如果單純的判斷是否相交,只需要看最後一個指針是否相等
    public static Node isIntersect(Node head1,Node head2){
        Node target=null;
        if(head1==null||head2==null)return target;
        int len1=getListLength(head1);
        int len2=getListLength(head2);
        if(len1>=len2){
            for(int i=0;i<len1-len2;i++){
                head1=head1.next;
            }
        }else{
            for(int i=0;i<len2-len1;i++){
                head2=head2.next;
            }
        }
        while(head1!=null&&head2!=null){
            if(head1==head2){
                target=head1;
                break;
            }
            else{
                head1=head1.next;
                head2=head2.next;
            }
        }
        return target;
    }
    //已知一個單鏈表中存在環,求進入環中的第一個節點,利用hashmap,不要用ArrayList,因爲判斷ArrayList是否包含某個元素的效率不高
    public static Node getFirstNodeInCycleHashMap(Node head){
        Node target=null;
        HashMap<Node,Boolean> map=new HashMap<Node,Boolean>();
        while(head!=null){
            if(map.containsKey(head))target=head;
            else{
                map.put(head, true);
            }
            head=head.next;
        }
        return target;
    }
    //已知一個單鏈表中存在環,求進入環中的第一個節點,不用hashmap
    //用快慢指針,與判斷一個單鏈表中是否有環一樣,找到快慢指針第一次相交的節點,此時這個節點距離環開始節點的長度和鏈表投距離環開始的節點的長度相等
    public static Node getFirstNodeInCycle(Node head){
        Node fast=head;
        Node slow=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;

    }
    //給出一單鏈表頭指針head和一節點指針delete,O(1)時間複雜度刪除節點delete
    //可惜採用將delete節點value值與它下個節點的值互換的方法,但是如果delete是最後一個節點,則不行,但是總得複雜度還是O(1)
    public static void deleteNode(Node head,Node delete){
        //首先處理delete節點爲最後一個節點的情況
        if(delete==null)return;
        if(delete.next==null){
            if(head==delete)head=null;
            else{
                Node temp=head;
                while(temp.next!=delete){
                    temp=temp.next;
                }
                temp.next=null;
            }
        }
        else{
            delete.value=delete.next.value;
            delete.next=delete.next.next;
        }
        return;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章