查詢效率最高即平均查詢長度最小,根據前面所學知識,我們可以給出有序表在非等概率情況下應遵循的兩個原則:
1、最先訪問的結點應是訪問概率最大的結點;
2、每次訪問應使結點兩邊尚未訪問的結點的被訪概率之和盡可能相等。
這兩個原則可用一句話來表示,即判定樹為帶權內路徑長度之和最小的二叉樹,亦即:ph = ∑wihi 最小,其中 n 為有序表長度,hi 為第 i 個結點在判定樹上的層次數,wi = cpi,c 為某個常數,pi 為第 i 個結點的查詢概率。
這樣的樹稱為靜態最優查詢樹(static optimal search tree),構造這樣一棵樹的時間代價太大,亦即時間複雜度很大,因此我們通常是構造次優查詢樹(nearly optimal search tree),構造它的時間代價遠遠低於構造最優查詢樹,但查詢效能只比最優查詢樹差1%~2%,很少差3%以上。
次優查詢樹的構造:
設有序表每個記錄的權值為 wl,wl+1,…,wh,第乙個應訪問的結點號為 i ,則有:
δpi = ∑wj - ∑wj 最小,即 δpi = min
再分別對 和 分別構造次優查詢樹。
為便於計算,引入累計權值swi=∑wj,並設wl-1=swl-1=0,則:
由於在構造次優查詢樹時沒有考慮前面說的原則一,因此被選為根的結點的權值可能比其鄰近結點的權值小,此時應對查詢樹作適當的調整,將相鄰權值大的結點作為根結點。
次優查詢樹的查詢方法與折半查詢類似,其平均查詢長度與 log n 成正比。
注意:利用上述演算法構造好次優二叉樹之後,可能並不是最優的,因為在構造過程中,沒有考慮單個關鍵字的相應權值,則有可能出現被選為根的關鍵字的權值比與
它相鄰的關鍵字的權值小。此時應做適當的調整:選取鄰近的權值較大的關鍵字作為次優查詢樹的根節點(也就是左旋和右旋子樹
#include#include#include#include#include#include#define n 100
#define maxn 0x3f3f3f3f
using namespace std;
templateclass treenode
};templateclass nearlyoptimalsearchtree;
templatevoid nearlyoptimalsearchtree::input()
templatevoid nearlyoptimalsearchtree::init()
}t = new treenode;
t->val = val[i];
t->w = w[i];
if(ld==rd) return;
buildt(ld, i-1, t->child[0]);
buildt(i+1, rd, t->child[1]);
}templatevoid nearlyoptimalsearchtree::adjustment(treenode* &t) else
}adjustment(t->child[0]);
adjustment(t->child[1]);
}templatevoid nearlyoptimalsearchtree::rotatet(treenode* &o, int x)
templatevoid nearlyoptimalsearchtree::outt(treenode* t)
int main()
/* 演示結果如下:
a 1b 1
c 2d 5
e 3f 4
g 4h 3
i 5沒有調整前的先序遍歷:
f d b a c e g h i
調整後的先序遍歷:
d c b a f e g i h
a 1b 30
c 2d 29
e 2沒有調整前的先序遍歷:
c b a d e
調整後的先序遍歷:
b a d c e
*/
#include#include#include#include#include#include#include#include#define n 100
#define maxn 0x3f3f3f3f
using namespace std;
templateclass treenode
};templateclass nearlyoptimalsearchtree;
templatevoid nearlyoptimalsearchtree::input()
templatevoid nearlyoptimalsearchtree::init()
}t = new treenode;
t->val = val[i];
t->w = w[i];
if(ld==rd) return;
buildt(ld, i-1, t->child[0]);
buildt(i+1, rd, t->child[1]);
}templatevoid nearlyoptimalsearchtree::adjustment(treenode* &t) else
}adjustment(t->child[0]);
adjustment(t->child[1]);
}templatevoid nearlyoptimalsearchtree::rotatet(treenode* &o, int x)
templatevoid nearlyoptimalsearchtree::widtht(treenode* t)
templatevoid nearlyoptimalsearchtree::outt(treenode* t) else
}//放入孩子節點
if(tt->child[0]) q.push(tt->child[0]), ++nn;
if(tt->child[1]) q.push(tt->child[1]), ++nn;
++i;
if(i>n) else
first = false;
if(qq.empty())
}printf("\n");
if(q.empty()) break;//這是最後一層
cout
nost.input();
nost.init();
return 0;}/*
//演示結果
a 1b 1
c 2d 5
e 3f 4
g 4h 3
i 5沒有調整前的先序遍歷:
f -------
| |d g
-------------
| | |
b e h
-----------------
| | |
a c i
調整後的先序遍歷:
d -------
| |
c f
-----------
| | |
b e g
-----------------
| |
a i
------------------|h
*/
次優查詢樹的建立
查詢效率最高即平均查詢長度最小,根據前面所學知識,我們可以給出有序表在非等概率情況下應遵循的兩個原則 1 最先訪問的結點應是訪問概率最大的結點 2 每次訪問應使結點兩邊尚未訪問的結點的被訪概率之和盡可能相等。這兩個原則可用一句話來表示,即判定樹為帶權內路徑長度之和最小的二叉樹,亦即 ph wihi ...
構造次優查詢樹
似乎有些錯誤,但是錯在哪了呢?include include using namespace std const int num 9 int value num float weight num float sum weight num void init sum weight struct tre...
靜態樹表查詢演算法 次優查詢樹
自 有關在靜態查詢表中對特定關鍵字進行順序查詢 折半查詢或者分塊查詢,都是在查詢表中各關鍵字被查詢概率相同的前提下進行的。例如查詢表中有 n 個關鍵字,表中每個關鍵字被查詢的概率都是 1 n。在等概率的情況,使用折半查詢演算法的效能最優。而在某些情況下,查詢表中各關鍵字被查詢的概率是不同的。例如水果...