次優查詢樹的實現【嚴蔚敏】
阿新 • • 發佈:2019-02-03
最優查詢樹:
用數學公式來表示就是:使得的PH值最小的樹為該陣列的靜態最優查詢樹。其中i為節點標號,為節點i的帶權路徑長度,,它等於結點i的查詢路徑長度c,乘以該結點被查詢的概率p;h表示節點i在搜尋樹中的高度。通俗點來說,就是權值越大的結點,越放到靠近根結點的位置。可能查詢概率大,需要的比較次數(折半查詢中的次數)多,或者兩者皆有。
次優二叉樹:
選出一個結點,使得它左右兩側的子陣列的權值累加和之差的絕對值最小。把這個結點當做根節點,遞迴地用剛才的左右字陣列構造它的左右子樹。
數學表示式:。
數學表示式:。
Status SecondOptimal(BiTree &T, ElemType R[],int sw[],int low,int high) { // 由有序表R[low..high]及其累計權值表sw(其中sw[0]==0)遞迴構造 // 次優查詢樹T。演算法9.3 int i,j; double min,dw; i=low; min=fabs(sw[high]-sw[low]); dw=sw[high]+sw[low-1]; for(j=low+1;j<=high;++j) // 選擇最小的△Pi值 if(fabs(dw-sw[j]-sw[j-1])<min) { i=j; min=fabs(dw-sw[j]-sw[j-1]); } if(!(T=(BiTree)malloc(sizeof(BiTNode)))) return ERROR; T->data=R[i]; // 生成結點 if(i==low) T->lchild=NULL; // 左子樹空 else SecondOptimal(T->lchild,R,sw,low,i-1); // 構造左子樹 if(i==high) T->rchild=NULL; // 右子樹空 else SecondOptimal(T->rchild,R,sw,i+1,high); // 構造右子樹 return OK; }
void FindSW(int sw[],SSTable ST)
{ // 按照有序表ST中各資料元素的Weight域求累計權值表sw
int i;
sw[0]=0;
for(i=1;i<=ST.length;i++)
sw[i]=sw[i-1]+ST.elem[i].weight;
}
程式碼完整實現:Status CreateSOSTree(SOSTree &T,SSTable ST) { // 由有序表ST構造一棵次優查詢樹T。ST的資料元素含有權域weight。演算法9.4 if(ST.length==0) T=NULL; else { FindSW(sw,ST); // 按照有序表ST中各資料元素的Weight域求累計權值表sw SecondOptimal(T,ST.elem,sw,1,ST.length); } return OK; }
// algo9-3.cpp 靜態查詢表(靜態樹表)的操作 #include <stdio.h> #include <malloc.h> #include <math.h> #include<iostream> //cout,cin using namespace std; // 函式結果狀態程式碼 #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define INFEASIBLE -1 // #define OVERFLOW -2 因為在math.h中已定義OVERFLOW的值為3,故去掉此行 typedef int Status; // Status是函式的型別,其值是函式結果狀態程式碼,如OK等 typedef int Boolean; // Boolean是布林型別,其值是TRUE或FALSE #define N 9 // 資料元素個數 #define EQ(a,b) ((a)==(b)) #define LT(a,b) ((a)<(b)) #define LQ(a,b) ((a)<=(b)) typedef char KeyType; // 設關鍵字域為字元型 struct ElemType // 資料元素型別(以教科書例9-1為例) { KeyType key; int weight; }r[N]={{'A',1},{'B',1},{'C',2},{'D',5},{'E',3}, {'F',4},{'G',4},{'H',3},{'I',5}}; // 全域性變數 int sw[N+1]; // 累計權值,全域性變數 typedef ElemType TElemType; typedef struct { ElemType *elem; // 資料元素儲存空間基址,建表時按實際長度分配,0號單元留空 int length; // 表長度 }SSTable; // 靜態查詢表(順序表和有序表)的基本操作(7個) Status Creat_Seq(SSTable &ST,int n) { // 操作結果: 構造一個含n個數據元素的靜態順序查詢表ST(資料來自全域性陣列r) int i; ST.elem=(ElemType*)calloc(n+1,sizeof(ElemType)); // 動態生成n個數據元素空間(0號單元不用) if(!ST.elem) return ERROR; for(i=1;i<=n;i++) *(ST.elem+i)=r[i-1]; // 將全域性陣列r的值依次賦給ST ST.length=n; return OK; } void Ascend(SSTable &ST) { // 重建靜態查詢表為按關鍵字非降序排序 int i,j,k; for(i=1;i<ST.length;i++) { k=i; ST.elem[0]=ST.elem[i]; // 待比較值存[0]單元 for(j=i+1;j<=ST.length;j++) if LT(ST.elem[j].key,ST.elem[0].key) { k=j; ST.elem[0]=ST.elem[j]; } if(k!=i) // 有更小的值則交換 { ST.elem[k]=ST.elem[i]; ST.elem[i]=ST.elem[0]; } } } Status Creat_Ord(SSTable &ST,int n) { // 操作結果: 構造一個含n個數據元素的靜態按關鍵字非降序查詢表ST // 資料來自全域性陣列r Status f; f=Creat_Seq(ST,n); if(f) Ascend(ST); return f; } Status Destroy(SSTable &ST) { // 初始條件: 靜態查詢表ST存在。操作結果: 銷燬表ST free(ST.elem); ST.elem=NULL; ST.length=0; return OK; } int Search_Seq(SSTable ST,KeyType key) { // 在順序表ST中順序查詢其關鍵字等於key的資料元素。若找到,則函式值為 // 該元素在表中的位置,否則為0。演算法9.1 int i; ST.elem[0].key=key; // 哨兵 for(i=ST.length;!EQ(ST.elem[i].key,key);--i); // 從後往前找 return i; // 找不到時,i為0 } int Search_Bin(SSTable ST,KeyType key) { // 在有序表ST中折半查詢其關鍵字等於key的資料元素。若找到,則函式值為 // 該元素在表中的位置,否則為0。演算法9.2 int low,high,mid; low=1; // 置區間初值 high=ST.length; while(low<=high) { mid=(low+high)/2; if EQ(key,ST.elem[mid].key) // 找到待查元素 return mid; else if LT(key,ST.elem[mid].key) high=mid-1; // 繼續在前半區間進行查詢 else low=mid+1; // 繼續在後半區間進行查詢 } return 0; // 順序表中不存在待查元素 } Status Traverse(SSTable ST,void(*Visit)(ElemType)) { // 初始條件: 靜態查詢表ST存在,Visit()是對元素操作的應用函式 // 操作結果: 按順序對ST的每個元素呼叫函式Visit()一次且僅一次。 // 一旦Visit()失敗,則操作失敗 ElemType *p; int i; p=++ST.elem; // p指向第一個元素 for(i=1;i<=ST.length;i++) Visit(*p++); return OK; } typedef struct BiTNode { TElemType data; BiTNode *lchild,*rchild; // 左右孩子指標 }BiTNode,*BiTree; Status SecondOptimal(BiTree &T, ElemType R[],int sw[],int low,int high) { // 由有序表R[low..high]及其累計權值表sw(其中sw[0]==0)遞迴構造 // 次優查詢樹T。演算法9.3 int i,j; double min,dw; i=low; min=fabs(sw[high]-sw[low]); dw=sw[high]+sw[low-1]; for(j=low+1;j<=high;++j) // 選擇最小的△Pi值 if(fabs(dw-sw[j]-sw[j-1])<min) { i=j; min=fabs(dw-sw[j]-sw[j-1]); } if(!(T=(BiTree)malloc(sizeof(BiTNode)))) return ERROR; T->data=R[i]; // 生成結點 if(i==low) T->lchild=NULL; // 左子樹空 else SecondOptimal(T->lchild,R,sw,low,i-1); // 構造左子樹 if(i==high) T->rchild=NULL; // 右子樹空 else SecondOptimal(T->rchild,R,sw,i+1,high); // 構造右子樹 return OK; } void FindSW(int sw[],SSTable ST) { // 按照有序表ST中各資料元素的Weight域求累計權值表sw int i; sw[0]=0; for(i=1;i<=ST.length;i++) sw[i]=sw[i-1]+ST.elem[i].weight; } typedef BiTree SOSTree; // 次優查詢樹採用二叉連結串列的儲存結構 Status CreateSOSTree(SOSTree &T,SSTable ST) { // 由有序表ST構造一棵次優查詢樹T。ST的資料元素含有權域weight。演算法9.4 if(ST.length==0) T=NULL; else { FindSW(sw,ST); // 按照有序表ST中各資料元素的Weight域求累計權值表sw SecondOptimal(T,ST.elem,sw,1,ST.length); } return OK; } Status Search_SOSTree(SOSTree &T,KeyType key) { // 在次優查詢樹T中查詢關鍵字等於key的元素。找到則返回OK,否則返回FALSE while(T) // T非空 if(T->data.key==key) return OK; else if(T->data.key>key) T=T->lchild; else T=T->rchild; return FALSE; // 順序表中不存在待查元素 } void print(ElemType c) // Traverse()呼叫的函式 { printf("(%c %d) ",c.key,c.weight); } int main() { SSTable st; SOSTree t; Status i; KeyType s; Creat_Ord(st,N); // 由全域性陣列產生非降序靜態查詢表st Traverse(st,print); CreateSOSTree(t,st); // 由有序表構造一棵次優查詢樹 printf("\n請輸入待查詢的字元: "); scanf("%c",&s); i=Search_SOSTree(t,s); if(i) printf("%c的權值是%d\n",s,t->data.weight); else printf("表中不存在此字元\n"); }