1. 程式人生 > >資料結構之單鏈表的幾個簡單演算法題

資料結構之單鏈表的幾個簡單演算法題

        單鏈表作為最基本的資料結構,在程式設計中有著非常重要的運用。最近自己閒下來,正在整理資料結構和演算法的一些程式題,現將自己的程式碼貼出來與大家分享。如有不對之處,請大家指正。(好吧 ,這麼簡單的題目應該不會有錯,都測試過了。況且說的好像很多人看我部落格一樣。好久沒更,都長草了……就當做寫給自己看的吧。:P)

package test;

import java.util.Hashtable;


class LinkNode{
	int value;
	LinkNode next;
	public LinkNode(int d){
		value = d;
	}
	public LinkNode(int d, LinkNode n){
		value = d;
		next = n;
	}
	
	/**
	 * 列印連結串列
	 */
	public static void printLinkedList(LinkNode head){
		LinkNode p = head;
		while( null != p ){
			System.out.print("" + p.value + " ");
			p = p.next;
		}
		System.out.println();
	}
}

/**
 * LinkNodeOperation
 * 1.刪除連結串列中重複的節點 
 * 2.找出單鏈表中倒數的第K個元素
 * 3.實現單鏈表的反轉
 * 4.實現單鏈表逆向輸出
 * 5.尋找單鏈表中間節點
 * 6.判斷兩條連結串列是否相交
 */
public class LinkNodeOperation {
	public static void main(String[] args){
		// 生成一條連結串列:
		LinkNode n4 = new LinkNode(19,null);
		LinkNode n3 = new LinkNode(20,n4);
		LinkNode n2 = new LinkNode(30,n3);
		LinkNode n1 = new LinkNode(40,n2);
		LinkNode head1 = new LinkNode(50,n1);
		// 生成一條值為0-20的連結串列,頭結點為2:
		LinkNode head = new LinkNode(2);
		LinkNode cur = null;
		for( int i=1; i<19; i++)
		{
			LinkNode temp = new LinkNode(i);
			if( i==1 )
			{ 
				head.next = temp;
			}
			else{
				cur.next = temp;
			}
			cur = temp;
		}
		cur.next = n4;
		//列印原始連結串列:
		System.out.print("原始連結串列:");
		LinkNode.printLinkedList(head);
		
		//列印原始連結串列:
		System.out.print("待判斷連結串列:");
		LinkNode.printLinkedList(head1);
		//判斷兩條連結串列是否相交:
		System.out.println("是否相交:"+ LinkNodeOperation.isIntersect(head, head1));
		
		//尋找連結串列的中間節點:
		System.out.print("連結串列的中間節點:");
		LinkNodeOperation.findMiddleElem(head);
		
		//從尾到頭輸出:
		System.out.print("從尾到頭輸出單鏈表:");
	    LinkNodeOperation.printLinklistReversely(head);
	    System.out.println();
	    
	    //列印倒數第K個節點:
	    LinkNodeOperation.findElem(head, 4);
	    System.out.println("----------------------------------------");
	    LinkNodeOperation.findElem2(head, 4);
	    System.out.println("----------------------------------------");
	    
	    //列印去重後的連結串列:
	    System.out.print("去重後的連結串列:");
	    LinkNodeOperation.deleteDuplicate2(head);
	    
	    //列印反轉後的連結串列
	    LinkNode.printLinkedList(head);
	    System.out.print("反轉後的連結串列:");
	    LinkNodeOperation.reverseElem(head);
	    
	}
	
	/**
	 * 使用HashTable去重
	 */
	public static void deleteDuplicate(LinkNode head){
		Hashtable<Integer, Integer> hashTable = new Hashtable<Integer, Integer>();
		LinkNode tmp = head;
		LinkNode pre = null;
		
		while(tmp != null){
			if(hashTable.containsKey(tmp.value)){
				pre.next = tmp.next;
			}else{
				hashTable.put(tmp.value, 1);
				pre = tmp;
			}
			tmp = tmp.next;
		}
	}
	/**
	 * 使用常規方法:雙重迴圈遍歷
	 */
	public static void deleteDuplicate2(LinkNode head){
		LinkNode p = head;
		while(p!=null){
			LinkNode q = p;
			while(q.next!=null){
				if(p.value == q.next.value){
					q.next = q.next.next;
				}
				else{
					q = q.next;
				}
			}
			p = p.next;
		}
	}
	
	/**
	 * 找出倒數第K個元素
	 * 方法1兩次遍歷
	 */
	public static void findElem(LinkNode head,int k){
		
		int count = 1;
		int index = 0;
		LinkNode p = head;
		while(p.next!= null){
			count++;
			p = p.next;
		}
		if( k<1 || k>count ){
			return;
		}
		System.out.println("--------------------------------");
		System.out.println("連結串列長度為:"+ count);
		
		while( head != null){
			index++;
			if(index == count-k+1){
				break;
			}
			head = head.next;
		}
		System.out.println("倒數第" + k + "個節點為:" + head.value);
	}
	
	/**
	 * 找出倒數第K個元素
	 * 方法2 雙指標 只需一次遍歷
	 */
	public static void findElem2(LinkNode head, int k){
		if(k<1){
			return;
		}
		LinkNode p = head;
		LinkNode q = head;
		// 讓P比Q先走K-1步
		for(int i=1; i<=k-1; i++){
			p = p.next;
		}
		while(p.next != null){
			p = p.next;
			q = q.next;
		}
		System.out.println("倒數第" + k +"個節點是:" + q.value );
	}
	
    /**
     * 連結串列反轉
     */
	public static void reverseElem(LinkNode head){
		LinkNode pre = head;
		LinkNode cur = head.next;
		LinkNode next= null;
		
		while(null != cur){
			next = cur.next;
			cur.next = pre;
			pre = cur;
			cur = next;
		}
		head.next = null;
		head = pre;
		LinkNode.printLinkedList(head);
	}
	
	/**
	 * 從尾到頭輸出單鏈表
	 * 方法:遞迴
	 */
	public static void printLinklistReversely(LinkNode head){
		if(head != null){
			printLinklistReversely(head.next);
			System.out.print(""+head.value+" ");
		}
	}
	
	/**
	 * 尋找單鏈表的中間節點
	 */
	public static void findMiddleElem(LinkNode head){
		LinkNode p = head;
		LinkNode q = head;
		while(p!=null && p.next!=null && p.next.next!=null ){
			p = p.next.next;
			q = q.next;
		}
		System.out.println(""+q.value);
	}
	
	/**
	 * 判斷兩條連結串列是否相交
	 */
	public static boolean isIntersect(LinkNode h1, LinkNode h2){
		if (h1==null || h2==null) {
			return false;
		}
		LinkNode tail1 = h1;
		LinkNode tail2 = h2;
		
		while(tail1.next!=null){
			tail1 = tail1.next;
		}
		while(tail2.next!=null){
			tail2 = tail2.next;
		}
		
		return tail1==tail2;
	}
}

執行結果: