各種查詢演算法效率比較
阿新 • • 發佈:2019-02-11
題目描述:
給定一個已經排好序的N個整數的序列(資料從1到N),在該序列中查詢指定的整數,並觀察不同演算法的執行時間。考查3類查詢演算法:折半查詢,平衡二叉排序樹的查詢,B-樹的查詢。
要求:
(1)構造樹表的演算法要考慮各種可能的輸入資料序列;
(2)可根據要求輸出樹表結構;
(3)分析最壞情況下,三種查詢演算法的複雜度;
(4)測量並比較三種演算法在N=100,500,1000,2000,4000,6000,8000,10000時的效能,要求完成以下三個方面的工作:
① 對每個測試資料集,統計計算每種查詢演算法的ASL;
② 對每個測試資料集執行多次獲得執行時間的平均值;
③ 繪製演算法實際執行結果(ASL和執行時間)的曲線圖,驗證和理論分析的時間複雜度的吻合性。
#include<iostream>
#include<stdio.h>
#include <time.h>
#include <malloc.h>
using namespace std;
#define CLOCKS_PER_SEC ((clock_t)1000)
#define MaxSize 100002
#define M 100
int Step;
int Bjishu;
using namespace std;
typedef struct
{
int key;
}DataType;
typedef struct
{
DataType list [MaxSize];
int size;
}SeqList;
typedef struct node
{
DataType data;
struct node *LeftChild;//
struct node *RightChild;//
struct node *Parent;
int i;//height
}BITreeNode, BTnode, *Tree;//二叉平衡樹結構體
typedef struct Node
{
struct Node *parent; /*指向雙親結點*/
int key[M]; /*關鍵字向量,0號單元未用(M-1階)*/
struct Node *ptr[M]; /*子樹指標向量*/
}B_TNode;//B_樹結構體
void ListInitiate(SeqList *L)
{
L->size = 0;
}
int ListLength(SeqList L)
{
return L.size;
}
int ListInsert(SeqList *L, int x)
{
// int j;
if (L->size >= MaxSize)
{
printf("順序表已滿\n");
return 0;
}
else
{
//for(j=L->size;j>i;j--)L->list[j]=L->list[j-1];
L->list[L->size].key = x;
L->size++;
return 1;
}
}
int BInarySearch(SeqList S, DataType x)//折半查詢
{
int js = 1; //次數記錄
int low = 0;
int high = S.size - 1;
int mid;
while (low <= high)
{
mid = (low + high) / 2; //中間位置
if (S.list[mid].key == x.key)return js;
else if (S.list[mid].key<x.key)low = mid + 1;
else if (S.list[mid].key>x.key)high = mid - 1;
js++;
}
return -1;
}
int Hetree(BTnode *Root)
{
if (Root == NULL)return 0;
return
Hetree(Root->LeftChild)>Hetree(Root->RightChild) ? Hetree(Root->LeftChild) + 1 : Hetree(Root->RightChild) + 1;
}
int IsBlance(BTnode *Root)//判斷二叉樹的平衡)
{
int bf;
if (Root != NULL)
{
bf = Hetree(Root->LeftChild) - Hetree(Root->RightChild);
if ((bf<-1) || (bf>1))
return 0;//不平衡
else
{
if (IsBlance(Root->LeftChild) && IsBlance(Root->RightChild))
return 1;
else
return 0;
}
}
return 1;
}
BTnode *R_Rotate(BTnode *Root, BTnode *p)//LL型調平衡(右旋)
{
BTnode *b, *q, *c, *d;
q = p->Parent;
b = p->LeftChild;
c = b->LeftChild;
d = b->RightChild;
p->LeftChild = d;
if (d != NULL)
d->Parent = p;
b->RightChild = p;
p->Parent = b;
if (q == NULL)
{
Root = b;
b->Parent = NULL; //b的父結點為空,即b就是根結點
}
else if (q->LeftChild == p) //如果a是父結點的左孩子
{
q->LeftChild = b; //將b賦值給q的左孩子
b->Parent = q; //b的父結點是q
}
else if (q->RightChild == p) //如果a是父結點的右孩子
{
q->RightChild = b; //將b賦值給q的右孩子
b->Parent = q; //b的父結點是q
}
return Root;
}
BTnode *L_Rotate(BTnode *Root, BTnode *p)//RR型調平衡
{
BTnode *b, *q, *c, *d;
q = p->Parent;
b = p->RightChild;
c = b->RightChild;
d = b->LeftChild;
p->RightChild = d;
if (d != NULL)
d->Parent = p;
b->LeftChild = p;
p->Parent = b;
if (q == NULL)
{
Root = b; //二叉樹的根結點就是b,把b賦值給樹Root
b->Parent = NULL; //b的父結點為空,即b就是根結點
}
else if (q->LeftChild == p) //如果p是父結點的左孩子
{
q->LeftChild = b; //將b賦值給q的左孩子
b->Parent = q; //b的父結點是q
}
else if (q->RightChild == p) //如果p是父結點的右孩子
{
q->RightChild = b; //將b賦值給q的右孩子
b->Parent = q; //b的父結點是q
}
return Root;
}
BTnode *LR_Rotate(BTnode *Root, BTnode *p)
{
BTnode *b, *q, *c, *d;
q = p->Parent;
b = p->LeftChild;
c = b->LeftChild;
d = b->RightChild;
p->LeftChild = d;
if (d != NULL)
d->Parent = p;
b->RightChild = p;
p->Parent = b;
if (q == NULL)
{
Root = b;
b->Parent = NULL; //b的父結點為空,即b就是根結點
}
else if (q->LeftChild == p) //如果a是父結點的右孩子
{
q->LeftChild = b; //將b賦值給q的左孩子
b->Parent = q; //b的父結點是q
}
else if (q->RightChild == p) //如果a是父結點的左孩子
{
q->RightChild = b; //將b賦值給q的右孩子
b->Parent = q; //b的父結點是q
}
return Root;
}
BTnode *RL_Rotate(BTnode *Root, BTnode *p)
{
BTnode *b, *q, *c, *d;
q = p->Parent;
b = p->RightChild;
c = b->RightChild;
d = b->LeftChild;
p->RightChild = d;
if (d != NULL)
d->Parent = p;
b->LeftChild = p;
p->Parent = b;
if (q == NULL)
{
Root = b; //二叉樹的根結點就是b,把b賦值給樹Root
b->Parent = NULL; //b的父結點為空,即b就是根結點
}
else if (q->LeftChild == p) //如果p是父結點的右孩子
{
q->LeftChild = b; //將b賦值給q的左孩子
b->Parent = q; //b的父結點是q
}
else if (q->RightChild == p) //如果p是父結點的左孩子
{
q->RightChild = b; //將b賦值給q的右孩子
b->Parent = q; //b的父結點是q
}
return Root;
}
int blancebinarytreesearch(BTnode *Root, int x)//查詢平衡二叉排序樹
{
BTnode *p;
int count = 0;
if (Root != NULL)
{
p = Root;
while (p != NULL)
{
count++;
if (p->i == x)return count;
else if (x<p->i)p = p->LeftChild;
else if (x>p->i)p = p->RightChild;
}
}
return 0;
}
int InPEtree(BTnode **Root, int x)//建立平衡二叉排序樹的函式
{
BTnode *cur, *parent = NULL, *p, *q;
cur = *Root;
while (cur != NULL)
{
if (x == cur->i)return 0;
parent = cur;
if (x<cur->i)cur = cur->LeftChild;
else if (x>cur->i)cur = cur->RightChild;
}
p = (BTnode *)malloc(sizeof(BTnode));
p->i = x;
p->LeftChild = NULL;
p->RightChild = NULL;
p->Parent = NULL;
if (parent == NULL)*Root = p;
else if (x<parent->i)
{
parent->LeftChild = p;
p->Parent = parent;
}
else if (x>parent->i)
{
parent->RightChild = p;
p->Parent = parent;
}
int bf;
if (IsBlance(*Root) == 0) //如果二叉樹是不平衡的
{
bf = Hetree(parent->LeftChild) - Hetree(parent->RightChild);
while ((bf >= -1) && (bf <= 1))
{
parent = parent->Parent;
bf = Hetree(parent->LeftChild) - Hetree(parent->RightChild);
}
q = parent;///找到離插入點最近的不平衡點
if (p->i>q->i&&p->i>q->RightChild->i)//新結點插入在q結點的右孩子的右子樹中。
{
*Root = L_Rotate(*Root, q);
}
else if (p->i>q->i&&p->i<q->RightChild->i)//新結點插入在A結點的右孩子的左子樹中
{
*Root = RL_Rotate(*Root, q);
}
else if (p->i<q->i&&p->i>q->LeftChild->i)//新結點插入在q結點的左孩子的右子樹中
{
*Root = LR_Rotate(*Root, q);
}
else //結點插入在A結點的左孩子的左子樹中
{
*Root = R_Rotate(*Root, q);
}
}
return 1;
}
void PrintBiTree(BTnode *root, int n)
{
int i;
if (root == NULL)return;
PrintBiTree(root->RightChild, n + 1);
for (i = 0; i<n - 1; i++)printf(" ");
if (n>0)
{
printf("-----");
printf("%d\n", root->i);
}
if (n == 0)
{
//printf("--");
printf("%d\n", root->i);
}
PrintBiTree(root->LeftChild, n + 1);
}
int B_treetreesearch(B_TNode *Root, int x)//查詢B-樹
{
int i;
if (Root == NULL)return 0;
for (i = 1; i <= Root->key[0]; i++)
{
Bjishu++;
if (x<Root->key[i])break;
if (x == Root->key[i])return Bjishu;
}
return B_treetreesearch(Root->ptr[i - 1], x);
}
B_TNode* B_treetreeinsert(B_TNode *Root, int x)//3.B-樹的插入函式
{
int i;
if (Root == NULL)//B_樹為空
{
Root = (B_TNode *)malloc(sizeof(B_TNode));
Root->key[0] = 1;
Root->key[1] = x;
for (i = 0; i<M; i++)
Root->ptr[i] = NULL;
Root->parent = NULL;
return Root;
}
B_TNode *p = Root, *q, *s;
q = p;
while (p != NULL)
{
for (i = 1; i <= p->key[0]; i++)
if (x<p->key[i])break;
q = p;
p = p->ptr[i - 1];
}
int j;
q->key[i] = x;
for (j = q->key[0]; j >= i; j--)
{
q->key[j + 1] = q->key[j];
q->ptr[j + 1] = q->ptr[j];
}
q->key[0]++;
int temp;
i = q->key[0];
int m, num = 0;
while (q->key[0] == Step + 1 - 1)
{
num++;
temp = q->key[(i - 1) / 2 + 1];
p = q->parent;
q->key[0] = (i - 1) / 2;//分裂左樹
m = (i - 1) / 2 + 1;
//加到雙親結點
if (p == NULL)
{
p = (B_TNode *)malloc(sizeof(B_TNode));
for (i = 0; i<M; i++)
p->ptr[i] = NULL;
Root = p;
Root->parent = NULL;
p->key[0] = 1;
p->key[1] = temp;
p->ptr[0] = q;
p->parent = NULL;
}
else
{
for (i = 1; i <= p->key[0]; i++)
if (temp<p->key[i])break;
for (j = p->key[0]; j >= i; j--)
{
p->key[j + 1] = p->key[j];
p->ptr[j + 1] = p->ptr[j];
}
p->key[i] = temp;//
p->ptr[i - 1] = q;//
p->key[0]++;
}
//分配右樹
s = (B_TNode *)malloc(sizeof(B_TNode));
for (i = 0; i<M; i++)
s->ptr[i] = NULL;
p->ptr[p->key[0]] = s;
p->ptr[p->key[0] - 1] = q;
s->key[0] = Step + 1 - 1 - m;
s->parent = p;
q->parent = p;
for (i = 1; i <= s->key[0]; i++)
{
s->key[i] = q->key[i + m];
s->ptr[i - 1] = q->ptr[i + m - 1]; ////////////////
}
if (num>1)s->ptr[i - 1] = q->ptr[i + m - 1];
for (i = 0; i <= s->key[0]; i++)
{
if (s->ptr[i] != NULL)s->ptr[i]->parent = s;////////////////
}
q = p;
i = q->key[0];
}
return Root;
}
int B_treetreeprint(B_TNode *Root, int n)
{
int i, j;
if (Root == NULL)return 0;
for (i = Root->key[0]; i>0; i--)
{
B_treetreeprint(Root->ptr[i], n + 1);
for (j = 0; j<n; j++)
printf("----");
cout << Root->key[i] << endl;
}
B_treetreeprint(Root->ptr[0], n + 1);
}
/*
int B_treetreeprint(B_TNode *Root,int n)
{
int i;
if(Root==NULL)return 0;
if(Root->key[0]>=2)
{
B_treetreeprint(Root->ptr[2],n+1);
for(i=0;i<n;i++)
printf("--");
printf("%d ",Root->key[2]);
printf("\n");
}
if(Root->key[0]>=1)
{
B_treetreeprint(Root->ptr[1],n+1);
for(i=0;i<n;i++)
printf("--");
printf("%d ",Root->key[1]);
printf("\n"); //printf("\n");
}
if(Root->ptr[0]!=NULL)
{
B_treetreeprint(Root->ptr[0],n+1);
// for(i=0;i<n;i++)
// printf("---");
}
}
int B_treetreeprint(B_TNode *Root,int n)
{
int i;
if(Root==NULL)return 0;
if(Root->key[0]>=2)
{
B_treetreeprint(Root->ptr[2],n+1);
for(i=0;i<n;i++)
printf("--");
printf("%d ",Root->key[2]);
printf("\n");
}
if(Root->key[0]>=1)
{
B_treetreeprint(Root->ptr[1],n+1);
for(i=0;i<n;i++)
printf("--");
printf("%d ",Root->key[1]);
printf("\n"); //printf("\n");
}
if(Root->ptr[0]!=NULL)
{
B_treetreeprint(Root->ptr[0],n+1);
// for(i=0;i<n;i++)
// printf("---");
}
}
*/
int main()
{
int i;
int s, j, k, k1, k2, k3, Size, Sizex;
int x;
SeqList L;
DataType Me;
double runtime;
double Start, End;
printf("請輸入序列中數的個數Size:");
//while (scanf("%d", &Size) != EOF&&Size != 0)
scanf("%d", &Size);
{
ListInitiate(&L); //初始化線性表
Tree t = NULL; //初始化二叉平衡樹
Tree zt = NULL; //初始化折半查詢樹
B_TNode *Root = NULL;
s = 0;
printf("請輸入B_樹的階:");
scanf("%d", &Step);
for (i = 0; i<Size; i++)
{
InPEtree(&t, i + 1); //Insert (&t,i+1);建立二叉平衡樹
ListInsert(&L, i + 1);//建立線性表
Root = B_treetreeinsert(Root, i + 1);//建立B_樹
}
printf("平衡二叉樹\n");
PrintBiTree(t, 0);//列印二叉平衡樹PrintfTree(t,1);
printf("\nB_樹\n");
B_treetreeprint(Root, 0);
//printf("請輸入需要查詢的數(1~Size):");
Sizex = Size;
printf("輸入要查詢的數\n");
scanf("%d",&Sizex);
if (Sizex <0 || Sizex >Size)
{
printf("查詢失敗,不存在此數!\n");
return 0;
}
//while (Sizex >= 1)
{
k1 = 0; k2 = 0; k3 = 0; //記次數
k1 = blancebinarytreesearch(t, Sizex);
printf("平衡二叉樹查詢%d用了%d次\n", Sizex, k1);
Me.key = Sizex;
k2 = BInarySearch(L, Me);
printf("折半查詢法查詢%d用了%d次\n", Sizex, k2);
Bjishu = 0;
printf("B_樹查詢%d用了%d次\n", Sizex, B_treetreesearch(Root, Sizex));
//printf("請輸入需要查詢的數(1~Size):");
}
k = 0;
Start = clock();//開始計時
for (i = 0; i<Size; i++)
{
k += blancebinarytreesearch(t, i + 1);//SearchBST(t,i+1,s);
}
End = clock();//結束計時】
runtime = (double)(End - Start) / (CLOCKS_PER_SEC*Size);
printf("%d個數的陣列\n\t\t 平衡二叉排序樹ASL= %.2f \t平均時間:%lf ms\n", Size, (float)k / Size, runtime);
k = 0;
Start = clock();
for (i = 0; i<Size; i++)
{
Me.key = i + 1;
k += BInarySearch(L, Me);
}
End = clock();
runtime = (double)(End - Start) / (CLOCKS_PER_SEC*Size);
printf("\t\t 折半查詢法ASL= %.2f \t 平均時間:%lf ms\n", (float)k / Size, runtime);
Bjishu = 0;
Start = clock();
for (i = 0; i<Size; i++)
{
B_treetreesearch(Root, i + 1);
}
End = clock();
runtime = (double)(End - Start) / (CLOCKS_PER_SEC*Size);
printf("\t\t B_樹查詢ASL= %.2f \t 平均時間:%lf ms\n", (float)Bjishu / Size, runtime);
}
return 0;
}