查找->静态查找表->次优查找(静态树表)

文字描算

  之前分析顺序查找和折半查找的算法性能都是在“等概率”的前提下进行的,但是如果有序表中各记录的查找概率不等呢?换句话说,概率不等的情况下,描述查找过程的判定树为何类二叉树,其查找性能最佳?

  如果只考虑查找成功的情况,则使查找性能达最佳的判定树是其带权内路径长度之和PH值取最小的二叉树。

  其中n为二叉树上结点的个数(即有序表的长度);hi为第i个结点在二叉树上的层次数;结点的权wi=cpi(i=1,2,…,n),其中pi为结点的查找概率,c为某个常量。称PH值取最小的二叉树为静态最优查找树。由于构造静态最优查找树代价较高,在此介绍一种构造近似最优查找树的有效算法。该算法的过程描述如下:

  已知一个按关键字有序的记录序列,其中, 与每个记录相应的权值为

 

  首先在记录序列中取第i(l<=i && i<=h)个记录构造根结点,使得取最小值,然后分别对子序列构造两棵次优查找树,并分别设为根结点的左子树和右子树。 

 

示意图

 

 

算法分析

  从次优查找树的结构特定可知,其查找过程类似于折半查找。查找过程和二叉排序树算法类型,待二叉排序树会讲。由于查找过程是走了一条从根到待查记录所在节点(或叶子结点)的一条路径,进行过比较的关键字个数不超过树的深度,因此,次优查找树的平均查找长度和logn成正比。可见,在记录的查找概率不等时,可用次优查找树表示静态查找表,故又称为静态树表。

       另外,大量实验表明,次优查找树和最优查找树的查找性能之差仅仅为1%-2%,很少查过3%,而且构造次优查找树的算法的时间复杂度为nlogn。

代码实现

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 
  5 #define DEBUG
  6 #define EQ(a, b) ((a)==(b))
  7 #define LT(a, b) ((a)< (b))
  8 #define LQ(a, b) ((a)<=(b))
  9 #define MAX_SIZE 50
 10 
 11 typedef char KeyType;
 12 //数据元素类型
 13 typedef struct{
 14     //关键字
 15     KeyType key;
 16     //权值
 17     int weight;
 18 }ElemType;
 19 //静态查找表
 20 typedef struct{
 21     //数据元素存储空间基址,0号单元留空
 22     ElemType *elem;
 23     //表长度
 24     int length;
 25 }SSTable;
 26 //二叉链表, 次优查找树采用二叉链表的存储结构
 27 typedef struct{
 28     ElemType data;
 29     struct BiTNode *lchild;
 30     struct BiTNode *rchild;
 31 }BiTNode, *BiTree;
 32 
 33 //由有序表R[low,...,high]及累计权值表sw(其中sw[0]==0)递归构造次优查找树T
 34 BiTNode* SecondOptimal(ElemType R[], int sw[], int low, int high)
 35 {
 36     int i = low, j = 0;
 37     int min = abs(sw[high]-sw[low]);
 38     int dw = sw[high]+sw[low-1];
 39     //选择最小的<>Pi值
 40     for(j=low+1; j<=high; ++j){
 41         if(abs(dw-sw[j]-sw[j-1])<min){
 42             i = j;
 43             min = abs(dw-sw[j]-sw[j-1]);
 44         }
 45     }
 46 #ifdef DEBUG
 47     printf("i=%d, low=%d, high=%d\n", i, low, high);
 48 #endif
 49     //生成结点
 50     BiTNode* T = (BiTNode*)malloc(sizeof(BiTNode));
 51     T->data = R[i];
 52     T->lchild = T->rchild = NULL;
 53     if(i==low){
 54         //左子树空
 55         T->lchild = NULL;
 56     }else{
 57         //构造左子树
 58         T->lchild = SecondOptimal(R, sw, low, i-1);
 59     }
 60     if(i==high){
 61         //右子树空
 62         T->rchild = NULL;
 63     }else{
 64         //构造右子树
 65         T->rchild = SecondOptimal(R, sw, i+1, high);
 66     }
 67     return T;
 68 }
 69 
 70 //按照由有序表ST中各数据元素的weight域求累计权值表sw
 71 void FindSW(int sw[], SSTable ST)
 72 {
 73     int i = 1;
 74     sw[0] = 0;
 75     for(i=1; i<=ST.length; i++){
 76         sw[i] = sw[i-1]+ST.elem[i].weight;
 77     }
 78 #ifdef DEBUG
 79     printf("SW  : ");
 80     for(i=1; i<=ST.length; i++){
 81         printf("[%d]=%-3d  ", i, sw[i]);
 82     }
 83     printf("\n");
 84 #endif
 85     return ;
 86 }
 87 
 88 //由有序表ST构造一棵次优查找树. ST的数据元素含有权域weight
 89 BiTree CreateSOSTree(SSTable ST)
 90 {
 91     if(ST.length == 0)
 92         return NULL;
 93     else{
 94         int sw[MAX_SIZE+1] = {0};
 95         //按照由有序表ST中各数据元素的weight域求累计权值表sw
 96         FindSW(sw, ST);
 97         //由有序表ST.elem[low,...,high]及累计权值表sw(其中sw[0]==0)递归构造次优查找树并返回
 98         return (BiTree)SecondOptimal(ST.elem, sw, 1, ST.length);
 99     }
100 }
101 
102 //顺序打印有序表ST中的数据元素。
103 void print(SSTable SS){
104     printf("data: ");
105     int i = 0;
106     for(i=1; i<=SS.length; i++){
107         printf("[%d]=%c,%d  ", i, SS.elem[i].key, SS.elem[i].weight);
108     }
109     printf("\n");
110 }
111 
112 int PreOrderTraverse(BiTree T);    //先序遍历
113 int InOrderTraverse(BiTree T);    //中序遍历
114 int PostOrderTraverse(BiTree T);//后序遍历
115 
116 int main(int argc, char *argv[])
117 {
118     
119     KeyType key;
120     int weight;
121     int i = 1;
122     char tmp[10] = {0};
123 #ifdef DEBUG
124     ElemType arr[MAX_SIZE+1] = {{'0',0},{'A',1}, {'B',1}, {'C',2}, {'D',5}, {'E',3},{'F',4},{'G',4},{'H',3},{'I',5},};
125     i = 10;
126 #else
127     ElemType arr[MAX_SIZE+1];
128     while(1){
129         printf("输入 关键字,权值('0,0'是结束):");
130         memset(tmp, 0, sizeof(tmp));
131         scanf("%s", tmp);
132         sscanf(tmp, "%c,%d", &key, &weight);
133         if(key == '0' && weight ==0){
134             break;
135         }else{
136             arr[i].key = key;
137             arr[i].weight = weight;
138             i+=1;
139         }
140     }
141 #endif
142     SSTable SS;
143     SS.elem = arr;
144     SS.length = i-1;
145 #ifdef DEBUG
146     print(SS);
147 #endif
148     BiTree T = CreateSOSTree(SS);
149     printf("先序遍历:");
150     PreOrderTraverse(T);
151     printf("\n");
152     
153     printf("中序遍历:");
154     InOrderTraverse(T);
155     printf("\n");
156     
157     printf("后序遍历:");
158     PostOrderTraverse(T);
159     printf("\n");
160     return 0;
161 }
162 
163 int PreOrderTraverse(BiTree T){
164     if(T){
165         printf("%c,%d  ", ((BiTNode*)T)->data.key, ((BiTNode*)T)->data.weight);
166         PreOrderTraverse((BiTree)T->lchild);
167         PreOrderTraverse((BiTree)T->rchild);
168     }
169     return 0;
170 }
171 
172 int InOrderTraverse(BiTree T){
173     if(T){
174         InOrderTraverse((BiTree)T->lchild);
175         printf("%c,%d  ", ((BiTNode*)T)->data.key, ((BiTNode*)T)->data.weight);
176         InOrderTraverse((BiTree)T->rchild);
177     }
178     return 0;
179 }
180 
181 int PostOrderTraverse(BiTree T){
182     if(T){
183         PostOrderTraverse((BiTree)T->lchild);
184         PostOrderTraverse((BiTree)T->rchild);
185         printf("%c,%d  ", ((BiTNode*)T)->data.key, ((BiTNode*)T)->data.weight);
186     }
187     return 0;
188 }
次优查找(静态树表)

 

运行

 

posted on 2018-08-15 18:20  LiveWithACat  阅读(1507)  评论(0编辑  收藏  举报