算法与数据结构--二叉搜索树与自平衡二叉搜索树

这篇具有很好参考价值的文章主要介绍了算法与数据结构--二叉搜索树与自平衡二叉搜索树。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

0.字典(即c++的map)

算法与数据结构--二叉搜索树与自平衡二叉搜索树,算法与数据结构,数据结构,算法

注:字典的 "member运算" 指的是检查字典中是否存在某个特定的键的操作,即查询操作。

如果我们使用数组来实现字典/map,虽然使用二分法查询也可以达到logn,但是的话插入和删除太慢了。使用链表实现的话虽然插入和删除是O(1),但是查询的话达到了O(n),也不可取。

因此人们发明了自平衡二叉查找树,在保证查找效率的同时,又保证了插入和删除的效率,从而更好的实现字典。

c++的map和set就是用红黑树来实现的(一种特殊的自平衡二叉搜索树)。而unorder_map使用哈希表实现的。

1.二叉查找树--BST

在讲自平衡二叉搜索树之前,我们要先明白什么是二叉搜索树。

二叉查找树(Binary Search Tree),是具有如下性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

二叉搜索树作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势;所以应用十分广泛,例如在文件系统和数据库系统一般会采用这种数据结构进行高效率的排序与检索操作。

复杂度:使用二叉搜索树进行添加,删除,搜索的平均时间复杂度都为O(logn)

特点:

2.自平衡二叉查找树--AVL树

1.为什么要有AVL树

算法与数据结构--二叉搜索树与自平衡二叉搜索树,算法与数据结构,数据结构,算法

二叉查找树虽然平均添加,删除,查找效率为O(logn),但是却不稳定,比如像上面这张图,在最坏的情况下,也就是该二叉树不平衡的时候,效率又降到了O(n)。

所以我们要想办法让这颗二叉查找树平衡,让结点平均地分布在树的两侧,从而提高算法的稳定性,于是就发明了自平衡二叉搜索树,即AVL树。

2.AVL树的定义

算法与数据结构--二叉搜索树与自平衡二叉搜索树,算法与数据结构,数据结构,算法

3.如何构建AVL树

具体流程:

元素插入二叉搜索树中->判断结点是否平衡,具体是那种情况的不平衡->根据所处的不平衡情况进行不同的调整策略

当遇到结点不平衡时:

根据插入元素的落点,调整策略分为四种情况,插入元素落入以下4个子树的情况分别对应着四种状态。
算法与数据结构--二叉搜索树与自平衡二叉搜索树,算法与数据结构,数据结构,算法

【1】右旋--LL型状态

算法与数据结构--二叉搜索树与自平衡二叉搜索树,算法与数据结构,数据结构,算法

这时候对A结点,也就是根结点使用右旋操作进行调整。A连接左子树的右子树,A称为B的右子树。
算法与数据结构--二叉搜索树与自平衡二叉搜索树,算法与数据结构,数据结构,算法

【2】左旋--RR型状态

算法与数据结构--二叉搜索树与自平衡二叉搜索树,算法与数据结构,数据结构,算法

这时候对根结点使用左旋操作。

算法与数据结构--二叉搜索树与自平衡二叉搜索树,算法与数据结构,数据结构,算法

【3】先左旋后右旋--LR型状态

算法与数据结构--二叉搜索树与自平衡二叉搜索树,算法与数据结构,数据结构,算法

采用LR双旋。

算法与数据结构--二叉搜索树与自平衡二叉搜索树,算法与数据结构,数据结构,算法算法与数据结构--二叉搜索树与自平衡二叉搜索树,算法与数据结构,数据结构,算法

这个操作等效与先对B结点作左旋操作,再对A结点作右旋操作。

【4】先右旋后左旋--RL型状态

算法与数据结构--二叉搜索树与自平衡二叉搜索树,算法与数据结构,数据结构,算法

采用RL双旋。

算法与数据结构--二叉搜索树与自平衡二叉搜索树,算法与数据结构,数据结构,算法算法与数据结构--二叉搜索树与自平衡二叉搜索树,算法与数据结构,数据结构,算法

RL双旋等效于先对C右旋,再对A左旋。

具体代码

gpt生成,以后有时间再自己写一遍文章来源地址https://www.toymoban.com/news/detail-763282.html

#include <iostream>
#include <algorithm>

// AVL节点的定义
struct AVLNode {
    int data;
    AVLNode* left;
    AVLNode* right;
    int height;

    AVLNode(int value) : data(value), left(nullptr), right(nullptr), height(1) {}
};

// 获取节点的高度
int getHeight(AVLNode* node) {
    if (node == nullptr)
        return 0;
    return node->height;
}

// 计算平衡因子
int getBalanceFactor(AVLNode* node) {
    if (node == nullptr)
        return 0;
    return getHeight(node->left) - getHeight(node->right);
}

// 更新节点的高度
void updateHeight(AVLNode* node) {
    if (node != nullptr) {
        node->height = 1 + std::max(getHeight(node->left), getHeight(node->right));
    }
}

// 右旋转
AVLNode* rightRotate(AVLNode* y) {
    AVLNode* x = y->left;
    AVLNode* T2 = x->right;

    x->right = y;
    y->left = T2;

    updateHeight(y);
    updateHeight(x);

    return x;
}

// 左旋转
AVLNode* leftRotate(AVLNode* x) {
    AVLNode* y = x->right;
    AVLNode* T2 = y->left;

    y->left = x;
    x->right = T2;

    updateHeight(x);
    updateHeight(y);

    return y;
}

// 插入节点
AVLNode* insertNode(AVLNode* root, int key) {
    if (root == nullptr) {
        return new AVLNode(key);
    }

    if (key < root->data) {
        root->left = insertNode(root->left, key);
    } else if (key > root->data) {
        root->right = insertNode(root->right, key);
    } else {
        // 重复的键值不允许插入
        return root;
    }

    // 更新节点的高度
    updateHeight(root);

    // 获取平衡因子
    int balance = getBalanceFactor(root);

    // 进行旋转操作以保持平衡
    // 左子树不平衡
    if (balance > 1) {
        if (key < root->left->data) {
            // 左-左情况,进行右旋转
            return rightRotate(root);
        } else {
            // 左-右情况,先左旋转,再右旋转
            root->left = leftRotate(root->left);
            return rightRotate(root);
        }
    }

    // 右子树不平衡
    if (balance < -1) {
        if (key > root->right->data) {
            // 右-右情况,进行左旋转
            return leftRotate(root);
        } else {
            // 右-左情况,先右旋转,再左旋转
            root->right = rightRotate(root->right);
            return leftRotate(root);
        }
    }

    // 树保持平衡,直接返回根节点
    return root;
}

// 中序遍历 AVL 树
void inOrderTraversal(AVLNode* root) {
    if (root != nullptr) {
        inOrderTraversal(root->left);
        std::cout << root->data << " ";
        inOrderTraversal(root->right);
    }
}

int main() {
    AVLNode* root = nullptr;

    // 插入一些节点
    root = insertNode(root, 10);
    root = insertNode(root, 20);
    root = insertNode(root, 30);
    root = insertNode(root, 15);
    root = insertNode(root, 5);

    // 输出中序遍历结果
    std::cout << "In-order traversal of AVL tree: ";
    inOrderTraversal(root);
    std::cout << std::endl;

    return 0;
}

到了这里,关于算法与数据结构--二叉搜索树与自平衡二叉搜索树的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 数据结构与算法——树与二叉树篇详解

    数据结构与算法——树与二叉树篇详解

    树形结构是一种非常重要的 非线性结构 ,树形结构中数据元素之间具有 一对多 的逻辑关系。 1.1.1 树的定义 树是由n(n=0)个结点所构成的有限集合 当n=0时,称为空树 当n0时,n个结点满足以下条件 有且仅有一个称为根的结点 其余结点可分为m个互不相交的有限集合,且每一个

    2024年02月06日
    浏览(11)
  • 【数据结构】树与二叉树(十三):递归复制二叉树(算法CopyTree)

    【数据结构】树与二叉树(十三):递归复制二叉树(算法CopyTree)

      二叉树是一种常见的树状数据结构,它由结点的有限集合组成。一个二叉树要么是 空集 ,被称为 空二叉树 ,要么由一个根结点和两棵不相交的子树组成,分别称为 左子树 和 右子树 。每个结点最多有两个子结点,分别称为左子结点和右子结点。 引理5.1:二叉树中层数

    2024年02月01日
    浏览(11)
  • 数据结构与算法--二叉树与树(单选题含题解)

    数据结构与算法--二叉树与树(单选题含题解)

    1、对以下算法功能最准确的描述是()。 A.判断二叉树根结点值是否为e B.判断二叉树是否存在值为e结点 C.求二叉树中值为e结点的层次 D.求二叉树值为e的结点的个数 C 2、二叉树的形态 由 3 个结点可以构造出 ▁▁▁▁▁ 种不同形态的二叉树。 A.2 B.3 C.4 D.5 D 由n个结点可以构

    2024年02月03日
    浏览(11)
  • 【数据结构】树与二叉树

    【数据结构】树与二叉树

    树是一种 非线性的数据结构 ,它是由n(n=0)个有限结点组成一个具有层次关系的集合。 把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的 。它具有以下的特点: 有一个特殊的结点,称为根结点,根结点没有前驱结点 除根结点外,其余结点被分

    2024年02月11日
    浏览(12)
  • [数据结构] 树与二叉树

    [数据结构] 树与二叉树

    树是由 (n(n geq 0)) 个节点组成的有限集。当 (n = 0) 时,称为空树。 任意一棵非空树应满足以下两点: (1)有且仅有一个特定的称为根的节点; (2)当 (n 1) 时,其余节点可分为 (m(m0)) 个互不相交的有限集 (T_1, T_2, dots, T_m) ,其中每个集合本身又是一棵树,称为根的

    2024年03月09日
    浏览(32)
  • 数据结构--树与二叉树

    数据结构--树与二叉树

    树的定义 树是n(n =0)个节点的有限集。当n=0 时,称为空树 在任意一棵非空树中应满足 有且仅有一个特定的称为根的结点 当n1 时,其余节点可分为m(m0) 个互不相交的有限集T1,T2……Tm,其中每个集合本身又是一棵树,并且称为根的子树 树是一种逻辑结构,也是一种分层结构 树的

    2024年02月22日
    浏览(10)
  • 【数据结构】树与二叉树(中)

    目录 前言: 一、顺序存储结构: 二、堆: 1.堆的性质: 2.堆的性质: 3.堆的实现: Ⅰ.堆的初始化:  Ⅱ.堆的插入(含向上调整):  Ⅲ.堆的删除(含向下调整算法): Ⅳ.取堆顶的数据: Ⅴ.堆中的数据个数: Ⅵ.堆的判空:  Ⅶ.堆的销毁: 总结:         上篇文章中,

    2024年02月16日
    浏览(12)
  • 数据结构_树与二叉树

    数据结构_树与二叉树

    目录 1. 树的基本概念 1.1 树的定义 1.2 基本术语 1.3 树的性质 1.4 相关练习 2. 二叉树的概念 2.1 二叉树的概念及其主要特性 2.2 二叉树的存储结构 2.2.1 顺序存储结构 2.2.2 链式存储结构 2.3 相关练习 3. 二叉树的遍历和线索二叉树 3.1 二叉树的遍历 3.1.1 先序遍历 3.1.2 中序遍历 3.1

    2024年02月04日
    浏览(14)
  • Java数据结构与算法:二叉搜索树

    Java数据结构与算法:二叉搜索树 大家好,我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿! 在计算机科学中,二叉搜索树(Binary Search Tree,简称BST)是一种常见的树形数据结构,它具有良好的查找和插入性能。每

    2024年01月24日
    浏览(13)
  • 数据结构:图文详解 树与二叉树(树与二叉树的概念和性质,存储,遍历)

    数据结构:图文详解 树与二叉树(树与二叉树的概念和性质,存储,遍历)

    目录 一.树的概念 二.树中重要的概念 三.二叉树的概念 满二叉树 完全二叉树 四.二叉树的性质 五.二叉树的存储 六.二叉树的遍历 前序遍历 中序遍历  后序遍历  树是一种 非线性数据结构 ,它由节点和边组成。树的每个节点可以有零个或多个子节点,其中一个节点被指定为

    2024年02月04日
    浏览(8)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包