自組織鏈表
由於鏈表中,在某一時間段內每個元素使用的頻率不同,所以,依賴於這種特點,產生了自組織鏈表,來提高鏈表的查找效率。
自組織鏈表可以動態的組織鏈表,有很多種方法,這裏列舉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);
}