算法與數據結構【Java】:自組織鏈表

由於鏈表中,在某一時間段內每個元素使用的頻率不同,所以,依賴於這種特點,產生了自組織鏈表,來提高鏈表的查找效率。
自組織鏈表可以動態的組織鏈表,有很多種方法,這裏列舉4種:
    1、前移法:找到需要的元素之後,將它放到鏈表開頭
    2、換位法:找到需要的元素之後,將它和前驅交換位置
    3、計數法:在結點中記錄被訪問的次數,根據被訪問的次數,對鏈表進行排序
    4、排序法:根據鏈表結點本身的屬性進行排序
以前移法爲例,在應用訪問數據庫時,通常是某個用戶對與其相關的信息進行頻繁的操作。這樣,採用前移法時,就能將正在被訪問的元素放在鏈表開頭,大大提高了查找效率。

下面以前移法爲例,實現一個自組織鏈表。
該實現在普通單向鏈表的代碼上進行添加和修改,直接實現了前移法。

package autoOrganizedList;

public class LinkedList {
	
	public int length = 0;		//鏈表長度,該屬性不重要,下面的方法中也沒有用到,但是維護了該屬性
	public Node head = null;		//鏈表頭節點的指針
	public Node tail = null;		//鏈表尾節點的指針
	LinkedList(){
		
	}
	
	int isEmpty(){			//判斷鏈表是否爲空,頭指針爲0代表空
		return head == null?1:0;
	}

	//向鏈表頭添加數據
	void addToHead(int aValue){
		head = new Node(aValue, head);	//添加節點
		if (tail == null) tail = head;		//如果尾指針爲空,說明鏈表本身爲空,更新尾指針
		length++;	
	}

	//向鏈表尾添加數據
	void addToTail(int aValue){
		//如果尾指針爲空,說明鏈表本身爲空,更新尾指針和頭指針
		if (tail == null) head = tail = new Node(aValue);	
		//否則只更新尾指針
		else tail = tail.next = new Node(aValue);
		length++;
	}

	//從鏈表頭刪除數據
	int deleteFromHead(){	
		//如果鏈表爲空,無法刪除,返回-1
		if (head == null) return -1;
		//記錄被刪除的值
		int deletedValue = head.value;
		if (head == tail)	//如果鏈表只有一個結點,那麼刪除後頭和尾都爲空
			head = tail = null;
		else 
			head = head.next;
		length--;
		return deletedValue;	//返回被刪除的值
	}
	
	int deleteFromTail(){
		//如果鏈表爲空,無法刪除,返回-1
		if (head == null) return -1;
		//記錄被刪除的值
		int deletedValue = tail.value;
		if (head == tail)	//如果鏈表只有一個結點,那麼刪除後頭和尾都爲空
			head = tail = null; 
		else {
			Node now = null;
			for(now=head; now.next!=tail; now=now.next);		//遍歷鏈表,找到倒數第二個結點
			now.next = null;
			tail = now;
		}
		length--; 
		return deletedValue;	//返回被刪除的值
	}
	
	int deleteNode(int index){
		if (index <= 0) return -1;
		//如果鏈表爲空,無法刪除,返回-1
		if (head == null) return -1;
		Node now = null;
		int cnt = 1;	//計數器
		/*
			下面的循環作用:
					情況1:正常情況下,找到要刪除的結點的前一個結點;
					情況2:如果要刪除的結點序號大於總結點數,使得找到的值停止在NULL
		*/
		for(now=head; cnt+1<index && now!=null; cnt++,now=now.next);

		if(now == null) return -1; 	//情況2發生,直接返回
		//記錄被刪除的結點指針和值
		Node deletedNode = now.next;
		int deletedValue = deletedNode.value;
		
		//情況1:將該結點刪除
		if (cnt == index-1)
			now.next = now.next.next;
		length--;
		//如果末尾結點被刪除,更新tail
		if (deletedNode.next == null){
			tail = now;
		}	
		return deletedValue;
	}

	//向指定序號處插入結點
	void addNode(int value, int index){	//index starts from 1
		if (index <= 0) return;
		//處理鏈表爲空插入結點的情況
		if (head == null && index == 1)	{
			head = tail = new Node(value);
			length++;
			return ;
		}
		//處理在鏈表頭插入數據的情況
		if (index == 1){
			head = new Node(value, head);
			length++;
			return ;
		}
		Node aheadOfAdd = null;
		int cnt = 1;
		//循環找到要插入的結點之前的那個結點
		for (aheadOfAdd=head,cnt=1; aheadOfAdd!=null&&cnt+1<index; cnt++,aheadOfAdd=aheadOfAdd.next);
		//如果以上循環因爲條件“cnt+1<index”不成立而終止,則因爲要插入的結點序號超過了鏈表總大小
		if (index != cnt+1)
			return ;
		if (aheadOfAdd == null) 
			return ;

		aheadOfAdd.next = new Node(value, aheadOfAdd.next);
		length++;
		//如果向尾部插入了結點,更新tail
		if (aheadOfAdd.next.next == null) tail = aheadOfAdd.next;
	}
	

	
	void printSelf(){	//打印鏈表內容
		Node nodeToPrint = this.head;
		System.out.println("Content of LinkedList:");
		while(nodeToPrint != null){
			System.out.print(String.format("%d ", nodeToPrint.value));
			if(nodeToPrint == tail)
				System.out.print("tail is reached!\n");
			nodeToPrint = nodeToPrint.next;
		}	
		System.out.print("\n");
	}
	
	//判斷鏈表是否包含某個值
	Node contains(int value){
		for(Node now=head; now!=null; now=now.next)
			if (now.value == value)
				return now;
		return null;
	}
	
	int nodeIndex(int value){
		int cnt=0;
		Node now=null;
		if (head == null) return -1;
		for (cnt=1,now=head; now!=null && now.value!=value; now=now.next,cnt++);
		return cnt;
	}
	Node search(int value){
		Node now = contains(value);
		if (now == null)	return null;
		deleteNode(nodeIndex(value));
		addToHead(value);
		return head;
	}
	
	
	static public void main(String[] argv) {
		LinkedList list = new LinkedList();System.out.print(String.format("\t\t%d\n", list.length));
		list.addToHead(1);list.printSelf();System.out.print(String.format("\t\t%d\n", list.length));
		list.addToHead(2);list.printSelf();System.out.print(String.format("\t\t%d\n", list.length));
		list.addToHead(3);list.printSelf();System.out.print(String.format("\t\t%d\n", list.length));
		list.addToHead(4);list.printSelf();System.out.print(String.format("\t\t%d\n", list.length));
		list.addToTail(100);list.printSelf();System.out.print(String.format("\t\t%d\n", list.length));
		list.addToTail(101);list.printSelf();System.out.print(String.format("\t\t%d\n", list.length));
		list.addToTail(102);list.printSelf();System.out.print(String.format("\t\t%d\n", list.length));
		list.addToTail(103);list.printSelf();System.out.print(String.format("\t\t%d\n", list.length));
		//list.deleteNode(8);list.printSelf();System.out.print(String.format("\t\t%d\n", list.length));
		list.search(103);list.printSelf();System.out.print(String.format("\t\t%d\n", list.length));
		System.out.println(list.contains(21323)==null?0:1);
		
		
	}
	
}
class Node{
	public int value;	//存儲節點的值 
	Node next;	//存儲下一個節點的指針
	Node(int aValue){
		this.value = aValue;
		this.next = null;
	}
	Node(int aValue, Node aNext){	//構造函數,必須傳入結點的值,下一個節點默認爲NULL
		this.value = aValue;
		this.next = aNext;
	}	
};

 

發佈了86 篇原創文章 · 獲贊 59 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章