次優查找樹的建立

  查找效率最高即平均查找長度最小,根據前面所學知識,我們可以給出有序表在非等概率情況下應遵循的兩個原則:???

  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 {Δpj?}?
再分別對 {rl,rl+1,…,ri-1} 和 {ri+1,ri+2,…,rh} 分別構造次優查找樹。?
??
為便于計算,引入累計權值swi=∑wj,并設wl-1=swl-1=0,則:

查找構造靜態次優查找樹(SOST) - 薔薇閣 - 落落工作室

????
??????? 由于在構造次優查找樹時沒有考慮前面說的原則一,因此被選為根的結點的權值可能比其鄰近結點的權值小,此時應對查找樹作適當的調整,將相鄰權值大的結點作為根結點。

????????? 次優查找樹的查找方法與折半查找類似,其平均查找長度與 log n 成正比。

注意:利用上述算法構造好次優二叉樹之后,可能并不是最優的,因為在構造過程中,沒有考慮單個關鍵字的相應權值,則有可能出現被選為根的關鍵字的權值比與

    它相鄰的關鍵字的權值小。此時應做適當的調整:選取鄰近的權值較大的關鍵字作為次優查找樹的根節點(也就是左旋和右旋子樹

#include<iostream>
#include
<cstring> #include<cstdio> #include<algorithm> #include<string> #include<cmath> #define N 100 #define MAXN 0x3f3f3f3f using namespace std;template<typename T> class TreeNode{public:TreeNode* child[2];T val;int w; TreeNode(){child[0] = child[1] = NULL;} };template<typename T> class NearlyOptimalSearchTree{//次優查找樹 public:int n;T val[N];int w[N];int sw[N];TreeNode<T> *t;void input();void init();void outT(TreeNode<T>* t);private:void buildT(int ld, int rd, TreeNode<T>* &t);//建立次優查找樹 void adjustment(TreeNode<T>* &t);//調整次優查找樹 void rotateT(TreeNode<T>* &t, int x); };template<typename T> void NearlyOptimalSearchTree<T>::input(){cin>>n;for(int i=1; i<=n; ++i)cin>>val[i]>>w[i]; }template<typename T> void NearlyOptimalSearchTree<T>::init(){sw[0] = 0;for(int i=1; i<=n; ++i) sw[i] = sw[i-1]+w[i];buildT(1, n, t);cout<<"沒有調整前的先序遍歷:"<<endl;outT(t);adjustment(t);cout<<endl<<"調整后的先序遍歷:"<<endl;outT(t);cout<<endl; }template<typename T> void NearlyOptimalSearchTree<T>::buildT(int ld, int rd, TreeNode<T>* &t){if(ld > rd) return;int minN = MAXN;int i;for(int j=ld; j<=rd; ++j){int ans = sw[rd] - sw[j-1] - sw[j]; ans = abs(ans);if(minN > ans){minN = ans;i = j;}}t = new TreeNode<T>;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]); }template<typename T> void NearlyOptimalSearchTree<T>::adjustment(TreeNode<T>* &t){if(!t) return;int lmax = 0, rmax = 0;if(t->child[0]) lmax = t->child[0]->w;if(t->child[1]) rmax = t->child[1]->w;int maxVal = max(lmax, rmax);if(t->w < maxVal){if(maxVal == lmax){rotateT(t, 1);//右旋子樹 } else {rotateT(t, 0);//左旋子樹 } }adjustment(t->child[0]);adjustment(t->child[1]); }template<typename T> void NearlyOptimalSearchTree<T>::rotateT(TreeNode<T>* &o, int x){TreeNode<T>* k = o->child[x^1];o->child[x^1] = k->child[x];k->child[x] = o;o = k; }template<typename T> void NearlyOptimalSearchTree<T>::outT(TreeNode<T>* t){if(!t) return;cout<<t->val<<" ";outT(t->child[0]);outT(t->child[1]); }int main(){NearlyOptimalSearchTree<string> nost;nost.input();nost.init();return 0; }

/*
  演示結果如下:

9
A 1
B 1
C 2
D 5
E 3
F 4
G 4
H 3
I 5
沒有調整前的先序遍歷:
F D B A C E G H I
調整后的先序遍歷:
D C B A F E G I H

 

5
A 1
B 30
C 2
D 29
E 2
沒有調整前的先序遍歷:
C B A D E
調整后的先序遍歷:
B A D C E


*/

?

#include<iostream> 
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<string> 
#include<iomanip>
#include<cmath>
#include<queue>
#define N 100
#define MAXN 0x3f3f3f3f
using namespace std;template<typename T>
class TreeNode{public:TreeNode* child[2];T val;int w; int d;//距離屏幕左端的寬度 
        TreeNode(){child[0] = child[1] = NULL;}
};template<typename T>
class NearlyOptimalSearchTree{//次優查找樹 public:int n;T val[N];int w[N];int sw[N];TreeNode<T> *t;void input();void init();void outT(TreeNode<T>* t);private:int width;int step;void buildT(int ld, int rd, TreeNode<T>* &t);//建立次優查找樹 void adjustment(TreeNode<T>* &t);//調整次優查找樹 void rotateT(TreeNode<T>* &t, int x);void widthT(TreeNode<T>* t);//計算每個節點到屏幕左端的距離 
};template<typename T>
void NearlyOptimalSearchTree<T>::input(){cin>>n;for(int i=1; i<=n; ++i)cin>>val[i]>>w[i];
}template<typename T>
void NearlyOptimalSearchTree<T>::init(){sw[0] = 0;width = 0;step = 2;for(int i=1; i<=n; ++i)    sw[i] = sw[i-1]+w[i];buildT(1, n, t);cout<<"沒有調整前的先序遍歷:"<<endl;outT(t);adjustment(t);cout<<endl<<"調整后的先序遍歷:"<<endl;outT(t);cout<<endl;
}template<typename T>
void NearlyOptimalSearchTree<T>::buildT(int ld, int rd, TreeNode<T>* &t){if(ld > rd) return;int minN = MAXN;int i;for(int j=ld; j<=rd; ++j){int ans = sw[rd] - sw[j-1] - sw[j];    ans = abs(ans);if(minN > ans){minN = ans;i = j;}}t = new TreeNode<T>;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]);
}template<typename T>
void NearlyOptimalSearchTree<T>::adjustment(TreeNode<T>* &t){if(!t) return;int lmax = 0, rmax = 0;if(t->child[0]) lmax = t->child[0]->w;if(t->child[1]) rmax = t->child[1]->w;int maxVal = max(lmax, rmax);if(t->w < maxVal){if(maxVal == lmax){rotateT(t, 1);//右旋子樹 } else {rotateT(t, 0);//左旋子樹 
        } }adjustment(t->child[0]);adjustment(t->child[1]);
}template<typename T>
void NearlyOptimalSearchTree<T>::rotateT(TreeNode<T>* &o, int x){TreeNode<T>* k = o->child[x^1];o->child[x^1] = k->child[x];k->child[x] = o;o = k; 
}template<typename T>
void NearlyOptimalSearchTree<T>::widthT(TreeNode<T>* t){if(!t) return;widthT(t->child[0]);t->d = width;width+=step; widthT(t->child[1]);
}template<typename T>
void NearlyOptimalSearchTree<T>::outT(TreeNode<T>* t){width=0;widthT(t);queue<TreeNode<T>*> q, qq;q.push(t);int n=1;//當前層的節點個數 int i=1;//當前層第幾個節點 int nn=0;//統計下一次的節點的個數int pred;//前一個節點距離左屏幕的距離 while(!q.empty()){TreeNode<T>* tt = q.front();q.pop();qq.push(tt);if(tt != t){//不是根節點, 打印分枝豎線 if(i==1){printf("%*s", tt->d, "|");pred = tt->d;} else {printf("%*s", tt->d-pred, "|");pred = tt->d;}}//放入孩子節點 if(tt->child[0]) q.push(tt->child[0]), ++nn;if(tt->child[1]) q.push(tt->child[1]), ++nn;++i; if(i>n){//上一層訪問完畢 i=1;n = nn;nn = 0;printf("\n");bool first = true;//是否是這一行的第一個節點 int ld, rd; while(!qq.empty()){//打印上層節點字符 TreeNode<T>* tt = qq.front();qq.pop();if(first){cout<<setw(tt->d)<<tt->val;pred = tt->d;ld = tt->d;if(tt->child[0])ld = tt->child[0]->d; } else {cout<<setw(tt->d - pred)<<tt->val;pred = tt->d;}first = false;if(qq.empty()){//這一層的最后一個節點 rd = tt->d+1;if(tt->child[1])rd = tt->child[1]->d;}}printf("\n");if(q.empty()) break;//這是最后一層 cout<<setw(ld-1)<<"";for(int i=ld; i<=rd; ++i)printf("-") ;printf("\n");}}
}int main(){NearlyOptimalSearchTree<string> nost;nost.input();nost.init();return 0;
}

/*
  //演示結果

9
A 1
B 1
C 2
D 5
E 3
F 4
G 4
H 3
I 5
沒有調整前的先序遍歷:

 

F
-------
| |
D G
-------------
| | |
B E H
-----------------
| | |
A C I

 

調整后的先序遍歷:

 

D
-------
| |
C F
-----------
| | |
B E G
-----------------
| |
A I
------------------
|
H


*/

?

轉載于:https://www.cnblogs.com/hujunzheng/p/4657858.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/531458.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/531458.shtml
英文地址,請注明出處:http://en.pswp.cn/news/531458.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

(四)C語言之數組

講一下數組的相關知識&#xff0c;數組在以后的編程還是很重要的&#xff0c;希望大家認真學習&#xff0c;同時也勉勵自己。 歡迎加入嵌入式學習群&#xff1a;559601187 在C語言中使用數組必須先進行定義&#xff0c;數組屬于構造數據類型的一種&#xff0c;它是一組相同數據…

平衡二叉樹AVL插入

平衡二叉樹(Balancedbinary tree)是由阿德爾森-維爾斯和蘭迪斯(Adelson-Velskiiand Landis)于1962年首先提出的&#xff0c;所以又稱為AVL樹。 定義&#xff1a;平衡二叉樹或為空樹,或為如下性質的二叉排序樹: &#xff08;1&#xff09;左右子樹深度之差的絕對值不超過1; &…

C語言練習(一)

今天來講解一下數組相關的習題&#xff0c;鞏固昨天的知識 歡迎加入嵌入式學習群&#xff1a;559601187 1.對于二維數組首地址偏移。 二維數組數組名偏移一個數&#xff0c;地址偏移一行&#xff0c;針對這個問題后面會做一個詳細的講解 #include <stdio.h> int main() …

(五)C語言之二維數組

今天的第二個內容單獨拿出來講一下&#xff0c;對于初接觸C語言的人來說&#xff0c;這個知識點比較難懂&#xff0c;后面在講指針的時候我還會提到這部分的內容&#xff0c;看不懂的同學可以看后面的內容。 指針變量可以指向一維數組中的元素&#xff0c;當然也就可以指向二維…

平衡二叉樹AVL刪除

平衡二叉樹的插入過程: http://www.cnblogs.com/hujunzheng/p/4665451.html 對于二叉平衡樹的刪除采用的是二叉排序樹刪除的思路: 假設被刪結點是*p&#xff0c;其雙親是*f&#xff0c;不失一般性&#xff0c;設*p是*f的左孩子&#xff0c;下面分三種情況討論&#xff1a;  ⑴…

(六)C語言之函數

本篇文章分為三個部分講解&#xff0c;分別為函數、局部變量和全局變量、c語言存儲分區 &#xff08;一&#xff09;函數的定義和調用 函數&#xff1a;工程中最小的單位&#xff0c;為了實現某一功能的 函數的定義&#xff1a; 數據類型 函數名(數據類型 形參1&#xff0c;…

堆排序算法---屬于選擇排序

1.堆 堆實際上是一棵完全二叉樹&#xff0c;其任何一非葉節點滿足性質&#xff1a; Key[i]<key[2i1]&&Key[i]<key[2i2]或者Key[i]>Key[2i1]&&key>key[2i2] 即任何一非葉節點的關鍵字不大于或者不小于其左右孩子節點的關鍵字。 堆分為大頂堆和小頂堆…

(七)C語言之指針

c語言相比其他高級語言來說&#xff0c;更接近于對計算機硬件的操作&#xff0c;而指針的應用更是為我們對硬件的操作插上了翅膀&#xff0c;所以指針是嵌入式編程不可少的一部分&#xff0c;在一定意義上說&#xff0c;指針是c語言的精髓。 一、 什么是指針 在計算機中&#…

各種排序(數據結構復習之內部排序算法總結)

1.三種選擇排序&#xff08;簡單選擇排序&#xff0c;樹形選擇排序&#xff0c;堆排序&#xff09; #include<iostream> #include<cstring> #include<string> #include<queue> #include<map> #include<cstdlib> #include<cstdio> c…

(八)C語言之結構

今天來說一下C語言里的結構體(struct)、共用體(l聯合體)union、枚舉。 &#xff08;一&#xff09;結構體&#xff1a;struct 1.1 概念 是一種自定義的數據類型結構體是構造類型的一種不同數據類型的集合地址空間連續&#xff0c;每次分配最大數據類型的寬度占用內存為所有變…

插入排序之表插入排序

1.表插入排序只是求得一個有序的鏈表&#xff0c;它是修改指針的值來代替移動記錄&#xff0c;操作過程如下 2.但是這樣只能進行順序查找&#xff0c;不能進行隨機查找&#xff0c;為了能實現有序表的折半查找&#xff0c;需要對記錄進行重新排列。操作過程如下&#xff1a; 3.…

電容降壓LED驅動電路

電容降壓電路具有體積小、成本低、電流相對穩定等優點&#xff0c;可應用于小功率的LED驅動電路中&#xff0c;本文主要介紹了電容降壓電路的基本電路 圖一&#xff1a; 電容降壓式簡易電源的基本原理如圖一所示&#xff0c;C3為降壓電容器&#xff1b;D4為半波整流二極管&…

延時電路分析

延時電路經常會用到&#xff0c;RC電路是比較簡單的電路。在電路設計中經常會用到將電阻和電容正極連接&#xff0c;電阻另一端接上電源&#xff0c;電容負極接地。 簡單的延時電路 上面就是延時的電路圖了&#xff0c;延時的時間為T-ln((VCC-Vout)/VCC)RC&#xff0c;公式中的…

恒流電路的分析(一)

在這里分析一個簡單的LED恒流電路&#xff0c;軟件采用Multisim進行波形采集 一、元器件 R1為80KΩ左右的金屬膜電阻&#xff1b;Q選取耐壓值超過350V的VPN三極管&#xff1b;D選取2V左右的穩壓二極管(如1N4680)&#xff1b;C2選取10V、100UF以上的電解電容&#xff1b;R2選擇…

ST-LINK USB communication error解決方法

今天在用stlink-v2下載程序時出現ST-LINK USB communication error&#xff0c;突然就出現了這個問題&#xff0c;在網上找了好多解決辦法都不可以用&#xff0c;下面給出我的解決方案&#xff0c;文章末尾給出了網上的幾種解決辦法&#xff0c;僅供參考。 第一步&#xff1a;找…

ajax實現上傳文件

1.html部分 <input style"width: 280px" type"file" name"upLoadProjectPlan" id"upLoadProjectPlan" value"<%taskAppend.getTaskAllocationDoc()%>"/><a style"float: right; margin-right: 40px&qu…

利用STM32制作紅外測溫儀之硬件設計

最近受疫情的影響詳細大家都在家里沒事干&#xff0c;這里利用stm32最小系統做一個紅外測溫儀 這篇教程里我們來制作紅外測溫儀需要用到的硬件&#xff0c;關于PCB的工程文件&#xff0c;后文會給出。 &#xff08;一&#xff09;系統分析 由于我們的功能比較單一&#xff0c;…

如何在博客中插入背景音樂

1.首先進入網音樂官方網站&#xff1b; 2.查找自己喜歡的歌&#xff0c;看到如下界面 3.點擊"生成外鏈播放器" 4.看到下面的html代碼了嗎&#xff1f;將代碼進行復制。 5.進入博客園&#xff0c;點擊 "管理" ->"設置"&#xff0c; 將代碼復制…

常用存儲器介紹

注意&#xff1a;"易失/非易失"是指存儲器斷電后&#xff0c;它存儲的數據內容是否會丟失的特性。 &#xff08;一&#xff09;RAM和ROM 1.1 RAM RAM即隨機存儲器&#xff0c;它是指存儲器中的數據被讀入或者寫入與信息所在位置無關&#xff0c;時間都是相同的 1…

TortoiseGit與github實現項目的上傳

1. 下載并安裝相關軟件 這里主要涉及的軟件包括msysgit和TortoiseGit。 msysgit的下載地址&#xff1a;http://msysgit.googlecode.com/files/Git-1.7.4-preview20110204.exe TortoiseGit的下載地址&#xff1a;http://code.google.com/p/tortoisegit/downloads/list&#xff0…