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

自組織鏈表

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

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

#include<iostream>
#include<string>
#include<stdio.h>
using namespace std;

//節點類,代表鏈表的結點
class Node{
	public:
		int value;	//存儲節點的值 
		Node* next;	//存儲下一個節點的指針 
		Node(int aValue, Node* aNext = NULL){	//構造函數,必須傳入結點的值,下一個節點默認爲NULL
			this->value = aValue;
			this->next = aNext;
		}	
};

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

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

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

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

		if(now == 0) 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 == 0){
			tail = now;
		}	
		delete deletedNode;
		return deletedValue;
	}

	//向指定序號處插入結點
	void addNode(int value, int index){	//index starts from 1
		if (index <= 0) return;
		//處理鏈表爲空插入結點的情況
		if (head == 0 && 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!=0&&cnt+1<index; cnt++,aheadOfAdd=aheadOfAdd->next);
		//如果以上循環因爲條件“cnt+1<index”不成立而終止,則因爲要插入的結點序號超過了鏈表總大小
		if (!index == cnt+1)
			return ;
		if (aheadOfAdd == 0) 
			return ;

		//printf("%d\n", aheadOfAdd->value);
		aheadOfAdd->next = new Node(value, aheadOfAdd->next);
		length++;
		//如果向尾部插入了結點,更新tail
		if (aheadOfAdd->next->next == 0) tail = aheadOfAdd->next;
	}
	

	
	void printSelf(){	//打印鏈表內容
		Node* nodeToPrint = this->head;
		printf("Content of LinkedList:");
		while(nodeToPrint != NULL){
			printf("%d ", nodeToPrint->value);
			if(nodeToPrint == tail)
				printf("tail is reached!\n");
			nodeToPrint = nodeToPrint->next;
		}	
		printf("\n");
	}
	
	//判斷鏈表是否包含某個值
	Node* contains(int value){
		for(Node* now=head; now!=0; now=now->next)
			if (now->value == value)
				return now;
		return 0;
	}
	
	int nodeIndex(int value){
		int cnt=0;
		Node* now=0;
		if (head == 0) return -1;
		for (cnt=1,now=head; now!=0 && now->value!=value; now=now->next,cnt++);
		return cnt;
	}
	Node* search(int value){
		Node* now = contains(value);
		if (now == 0)	return 0;
		deleteNode(nodeIndex(value));
		addToHead(value);
		return head;
	}
};

//測試程序
int main(){

	LinkedList* list = new LinkedList();printf("		%d\n", list->length);
	list->addToHead(1);list->printSelf();printf("		%d\n", list->length);
	list->addToHead(2);list->printSelf();printf("		%d\n", list->length);
	list->addToHead(3);list->printSelf();printf("		%d\n", list->length);
	list->addToHead(4);list->printSelf();printf("		%d\n", list->length);
	list->addToTail(100);list->printSelf();printf("		%d\n", list->length);
	list->addToTail(101);list->printSelf();printf("		%d\n", list->length);
	list->addToTail(102);list->printSelf();printf("		%d\n", list->length);
	list->addToTail(103);list->printSelf();printf("		%d\n", list->length);
	//list->deleteNode(8);list->printSelf();printf("		%d\n", list->length);
	list->search(103);list->printSelf();printf("		%d\n", list->length);
	printf("%d",list->contains(21323)==0?0:1);
} 



 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章