二叉搜索树的代价讨论与优化的一种(上)

 1.二叉搜索树

      《数据结构与算法分析》一书中已经说过(p85)“不过,在没有使用删除或是懒惰删除的情况下,可以证明所有二叉查找树是等可能出现的,而且我们可以断言,上述那些操作的平均时间都是O(logN)”

先说结论,再没有删除的情况下,10万次的万次随机插入后10万次的万次访问操作的单次操作平均时间是O(logN)。

其中尽管出现了明显不平衡的树,但是上述结论依然适用。

为什么呢?

个人以为差距所在处为左右子节点的数量比率上,以一颗含有N个节点的二叉搜索树为例,除去根节点,左右子节点的数量比率越靠近常数级越好,越靠近O(n)越不妙。如果这棵树所有节点的比率都趋近于第二种情况,那么这棵树就会变成昂贵的单链表,它的单次操作平均时间将是O(N),但是这种概率就和这棵树所有节点的比率都趋近于第一种情况一样,即完美二叉树,概率极低。所以在这棵树中所有节点的比率大多出现在一二种情况中间,然而对树的深度起决定影响的是第二种情况的节点数量,如前所述,第二种情况的节点数量在随机插入N次的树中占比率极低,这也就是为什么随机插入N次的二叉树的节点平均深度能在O(logN),而不是O(N),所以结论单次操作平均时间是O(logN)成立。

以下给出二叉搜索树的代码实现(建议能人们自己敲,我的看看就行)

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
//11.28,二叉搜索树的实现与测试
typedef int Elem;

int count = 0;

typedef struct Treenode {
    Elem data;
    int deletion;
    //struct Treenode* parents;
    struct Treenode* leftchild;
    struct Treenode* rightchild;
}Treenode;

typedef Treenode* Treepoint;

static Treepoint MakeEmpty(Treepoint root) {
    if (root != NULL) {
        MakeEmpty(root->leftchild);
        MakeEmpty(root->rightchild);
        free(root);
    }
    return NULL;
}

static Treepoint Find(Treepoint root, Elem x) {
    count++;
    if (root == NULL)
        return NULL;
    if (x < root->data) {
        count++;
        return Find(root->leftchild, x);
    }
    else if (x > root->data) {
        count++;
        return Find(root->rightchild, x);
    }
    else
        return root;
}

static Treepoint FindMin(Treepoint root) {
    if (root == NULL)
        return NULL;
    else if (root->leftchild == NULL)
        return root;
    else
        return FindMin(root->leftchild);
}

static Treepoint FindMax(Treepoint root) {
    if (root == NULL)
        return NULL;
    else if (root->rightchild == NULL)
        return root;
    else
        return FindMin(root->rightchild);
}

static Treepoint Insert(Treepoint root, Elem x) {
    if (root == NULL) {
        root = (Treepoint)calloc(1, sizeof(Treenode));
        if (root != NULL) {
            root->data = x;
            root->deletion = 1;
            root->leftchild = NULL;
            root->rightchild = NULL;
        }
    }
    else {
        if (x < root->data)
            root->leftchild = Insert(root->leftchild, x);
        else if (x > root->data)
            root->rightchild = Insert(root->rightchild, x);
        else
            root->deletion++;
    }
    return root;
}

static Treepoint Delete(Treepoint root, Elem x) {
    if (root == NULL)
        printf("Error!");
    else if (x < root->data)
        root->leftchild = Delete(root->leftchild, x);
    else if (x > root->data)
        root->rightchild = Delete(root->rightchild, x);
    else {
        root->deletion--;
    }
    return root;
}

static void middle(Treepoint root) {
    if (root != NULL) {
        if (root->leftchild != NULL)
            middle(root->leftchild);
        if(root->deletion > 0)
            printf("%d(deletion:%3d)   ", root->data,root->deletion);
        //else
            //printf("%d(deletion:%3d)   ", root->data, root->deletion);
        if (root->rightchild != NULL)
            middle(root->rightchild);
    }
}

void test() {
    Treepoint root = Insert(NULL,1);//树的初始化
    //测试代码大家可自行编写,我的仅供参考
    srand((unsigned int)time(NULL));
    const int m = 100000;
    const int m2 = 100000000;
    int arr[m] = { 0 };
    for (int i = 0;i < m;i++) {
        arr[i] = rand() % m2;
    }
    for (int i = 0;i < m;i++) {
        Insert(root, arr[i]);
    }
    for (int i = 0;i < m;i++) {
        int k = rand() % m;
        root = Find(root, arr[k]);
}
    printf("\ncount = %d\n", count);
}

int main() {
    test();
    return 0;
}

代码仅供参考,还是那句话,佬们自己敲自己跑自己看结果。

2.二叉搜索树的优化--伸展树(splay tree)

敬请期待....(就快了)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值