1. 程式人生 > >經典案例-連結串列操作的幾大經典例子 單鏈表反轉 環的檢測 求中間節點 有序連結串列合併等

經典案例-連結串列操作的幾大經典例子 單鏈表反轉 環的檢測 求中間節點 有序連結串列合併等

這篇博文 主要總結連結串列在應用時的幾個重要案例。學習之前,最好能夠掌握連結串列相關的一些基礎知識,以及連結串列中資料的插入、刪除操作如何實現等等,這些網上資料很多,這裡沒有做過多介紹,不熟悉的同學可以看程式碼之前簡單瞭解一下。

1.單鏈表反轉    連結串列中環的檢測    求中間節點    刪除連結串列中第n個結點         刪除連結串列中倒數第n個節點

import java.util.Scanner;


/** 
 * @author xjh 2018.10.10
 *
 */
class Node{	//節點類
	int data;
	Node next;
	Node(int data){
		this.data=data;
	}
}
public class SingleLinkedeList {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner in=new Scanner(System.in);
		String t=in.nextLine();	//首先用String接收控制檯輸入的所有數字
		char[] s=t.toCharArray();	//轉換為char型
		Node[] node=new Node[s.length];
		
		for(int i=0;i<s.length;i++){
			node[i]=new Node(s[i]-'0');	//得到int型 存入單鏈表節點中				
		}
		for(int i=0;i<s.length;i++){
			if(i==s.length-1){	//最後一個節點,指標指向空
				node[i].next=null;	//null為單鏈表 node[0]則為迴圈連結串列
			}
			else node[i].next=node[i+1];
		}
		
		
		printAll(node[0]);			//首先輸出原有的連結串列順序 這裡如果時迴圈連結串列的話 則不能執行這條語句 因為會進入死迴圈
//		printAll(reverse(node[0]));	//輸出單鏈表反轉後的連結串列順序
		System.out.println("It's CircleLinkedList ? "+CheckCircle(node[0]));
		System.out.println("middleNode "+middleNode(node[0]).data);
		int delete=3;	//刪除第n個節點
//		printAll(deleteNode(node[0],delete));
		printAll(deleteNodeToEnd(node[0],delete));
	}
	
	public static void printAll(Node head){
		Node t=head;
		while(t!=null){
			System.out.print(t.data+" ");
			t=t.next;
		}		
		System.out.println();
	}
	
	/**
	 * 單鏈表反轉
	 * @param p
	 * @return head
	 */
	public static Node reverse(Node p){
		Node head=null;
		Node previousNode=null;	//先前節點指標
		Node currentNode=p;
		while(currentNode!=null){	//非空連結串列
			Node nextNode=currentNode.next;
			if(nextNode==null){	//以到達最後一個節點
				head=currentNode;
			}
			currentNode.next=previousNode;	//指向前面一個節點(頭節點則指向null)
			previousNode=currentNode;
			currentNode=nextNode;	//currentNode指向原來連結串列的下一個節點
		}
		return head;
	}
	/**
	 * 檢測來連結串列是否有環(迴圈連結串列)
	 * @param p
	 * @return
	 */
	public static boolean CheckCircle(Node p){
		if(p==null)
			return false;
		Node a=p;
		Node b=p;
		while(a!=null&&a.next!=null){
			//這裡利用快慢兩個指標 主要為了讓考慮如果連結串列長度特別大時,單一指標節點往後遍歷時間複雜度高
			a=a.next.next;
			b=b.next;
			if(a==b)
				return true;								
		}
		return false;
	}
	/**
	 * 求連結串列中間節點(注意這裡的求解方法只用在單鏈表中,不適合在迴圈連結串列)
	 * @param p
	 * @return
	 */
	public static Node middleNode(Node p){
		if(p==null)
			return null;
		Node a=p;
		Node b=p;
		while(a!=null&&a.next!=null){
			//這裡利用快慢兩個指標 主要為了讓考慮如果連結串列長度特別大時,單一指標節點往後遍歷時間複雜度高
			a=a.next.next;
			b=b.next;											
		}
		return b;	//b就是連結串列中間節點
	}
	/**
	 * 刪除連結串列中第n個結點 
	 * @param p
	 * @return
	 */
	public static Node deleteNode(Node p,int delete){
		Node n=p;
		while(n!=null&&--delete>1){
			n=n.next;
		}
		if(n==null)	//連結串列中一共沒有n個節點,無法實現刪除操作
			return p;
		n.next=n.next.next;	//刪除指定的元素
		return p;
	}
	/**
	 * 刪除連結串列中倒數第n個節點
	 * 思路:首先利用一個指標p1找到第n個節點,然後另外一個指標p2從頭節點出發 兩個指標往後遍歷,p1到達尾節點時 p2剛好為倒數第n個節點
	 * @param p
	 * @param delete
	 * @return
	 */
	public static Node deleteNodeToEnd(Node p,int delete){
		Node p1=p;
		int i=1;
		while(p1!=null&&i<delete){
			p1=p1.next;
			++i;
		}
		if(p1==null)	//連結串列一共沒有n個節點,無法實現刪除操作
			return p;
		
		Node p2=p;
		Node pre=null;
		while(p1.next!=null){
			//往後遍歷連結串列節點
			p1=p1.next;
			pre=p2;
			p2=p2.next;
		}//迴圈結束時 p1為尾節點,p2為倒數第n個節點 pre為倒數第n+1個節點
		pre.next=pre.next.next;
		return p;
	}
}

2.兩個有序連結串列的合併

import java.util.Scanner;

/**
 * 兩個有序單鏈表的合併
 * @author xjh 2018.10.10
 *
 */
public class SingleLinkedeList2 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//首先構建兩個升序單鏈表a b
		int[] t1={1,3,5,7,9};
		Node[] a=new Node[t1.length];
		for(int i=0;i<t1.length;i++){
			a[i]=new Node(t1[i]);	//得到int型 存入單鏈表節點中				
		}
		for(int i=0;i<t1.length;i++){
			if(i==t1.length-1){	//最後一個節點,指標指向空
				a[i].next=null;	//null為單鏈表 node[0]則為迴圈連結串列
			}
			else a[i].next=a[i+1];
		}
		
		int[] t2={2,4,6,8,10};
		Node[]b=new Node[t2.length];
		for(int i=0;i<t2.length;i++){
			b[i]=new Node(t2[i]);	//得到int型 存入單鏈表節點中				
		}
		for(int i=0;i<t2.length;i++){
			if(i==t2.length-1){	//最後一個節點,指標指向空
				b[i].next=null;	//null為單鏈表 node[0]則為迴圈連結串列
			}
			else b[i].next=b[i+1];
		}
		
		printAll(MergeSort(a[0],b[0]));
	}
	public static void printAll(Node head){
		Node t=head;
		while(t!=null){
			System.out.print(t.data+" ");
			t=t.next;
		}		
		System.out.println();
	}
	/**
	 * 合併兩個有序連結串列
	 * @param a
	 * @param b
	 * @return
	 */
	public static Node MergeSort(Node a,Node b){
		if(a==null) return b;
		if(b==null) return a;
		
		Node p=a;
		Node q=b;
		Node head;
		//首先確定合併連結串列的頭節點
		if(p.data<q.data){
			head=p;
			p=p.next;
		}else{
			head=q;
			q=q.next;
		}
		Node r=head;
		//兩個連結串列節點的元素依次進行比較,r指標有序連線
		while(p!=null&&q!=null){
			if(p.data<q.data){
				r.next=p;
				p=p.next;
			}else{
				r.next=q;
				q=q.next;
			}
			r=r.next;
		}
		//當某個連結串列遍歷提前結束時,r直接連線另一個為遍歷完的有序連結串列
		if(p!=null){
			r.next=p;
		}else{
			r.next=q;
		}
		return head;
	}
}