1. 程式人生 > >各種查詢演算法效率比較

各種查詢演算法效率比較

題目描述:
給定一個已經排好序的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; }