虚位以待(AD)
虚位以待(AD)
首页 > 软件编程 > C/C++编程 > C语言数据结构之平衡二叉树(AVL树)实现方法示例

C语言数据结构之平衡二叉树(AVL树)实现方法示例
类别:C/C++编程   作者:码皇   来源:互联网   点击:

这篇文章主要介绍了C语言数据结构之平衡二叉树(AVL树)实现方法,结合实例形式分析了C语言平衡二叉树的相关定义与使用技巧,需要的朋友可以参考下

本文实例讲述了C语言数据结构之平衡二叉树(AVL树)实现方法。分享给大家供大家参考,具体如下:

AVL树是每个结点的左子树和右子树的高度最多差1的二叉查找树。

要维持这个树,必须在插入和删除的时候都检测是否出现破坏树结构的情况。然后立刻进行调整。

看了好久,网上各种各种的AVL树,千奇百怪。

关键是要理解插入的时候旋转的概念。

    //// AvlTree.h// HelloWorld// Created by feiyin001 on 17/1/9.// Copyright (c) 2017年 FableGame. All rights reserved.//#ifndef __HelloWorld__AvlTree__#define __HelloWorld__AvlTree__#include <iostream>namespace Fable{
    int max(int a, int b) {
    return a > b? a:b;
    }
    //二叉查找树,对于Comparable,必须实现了><=的比较 template<typename Comparable> class AvlTree {
    public: //构造函数 AvlTree(){
    }
    //复制构造函数 AvlTree(const AvlTree& rhs) {
    root = clone(rhs.root);
    }
    //析构函数 ~AvlTree() {
    makeEmpty(root);
    }
    //复制赋值运算符 const AvlTree& operator=(const AvlTree& rhs) {
    if (this != &rhs) {
    makeEmpty(root);
    //先清除 root = clone(rhs.root);
    //再复制 }
    return *this;
    }
    //查找最小的对象 const Comparable& findMin()const {
    findMin(root);
    }
    //查找最大的对象 const Comparable& findMax()const {
    findMax(root);
    }
    //是否包含了某个对象 bool contains(const Comparable& x)const {
    return contains(x, root);
    }
    //树为空 bool isEmpty()const {
    return root == nullptr;
    }
    //打印整棵树 void printTree()const {
    printTree(root);
    }
    //清空树 void makeEmpty() {
    makeEmpty(root);
    }
    //插入某个对象 void insert(const Comparable& x) {
    insert(x, root);
    }
    //移除某个对象 void remove(const Comparable& x) {
    remove(x, root);
    }
    private: struct AvlNode {
    Comparable element;
    AvlNode* left;
    AvlNode* right;
    int height;
    AvlNode(const Comparable& theElement, AvlNode* lt, AvlNode* rt, int h = 0) :element(theElement), left(lt), right(rt), height(h){
    }
    }
    ;
    typedef AvlNode* AvlNodePtr;
    AvlNodePtr root;
    //根结点 //顺时针旋转 void clockwiseRotate(AvlNodePtr& a) {
    AvlNodePtr b = a->left;
    //左叶子 a->left = b->right;
    //a的左叶子变为b的右叶子,b本来的子结点都比a小的。 b->right = a;
    //b的右结点指向a,b的高度上升了。 a->height = max(height(a->left), height(a->right)) + 1;
    //重新计算a的高度 b->height = max(height(b->left), a->height) + 1;
    //重新计算b的高度 a = b;
    //a的位置现在是b,当前的根结点 }
    //逆时针旋转 void antiClockWiseRotate(AvlNodePtr& a) {
    AvlNodePtr b = a->right;
    //右结点 a->right = b->left;
    //a接收b的左结点 b->left = a;
    //自己成为b的左结点 a->height = max(height(a->left), height(a->right)) + 1;
    //计算高度 b->height = max(b->height, height(a->right)) + 1;
    //计算高度 a = b;
    //新的根结点 }
    //对左边结点的双旋转 void doubleWithLeftChild(AvlNodePtr& k3) {
    antiClockWiseRotate(k3->left);
    //逆时针旋转左结点 clockwiseRotate(k3);
    //顺时针旋转自身 }
    //对右边结点的双旋转 void doubleWithRightChild(AvlNodePtr& k3) {
    clockwiseRotate(k3->right);
    //顺时针旋转有节点 antiClockWiseRotate(k3);
    //逆时针旋转自身 }
    //插入对象,这里使用了引用 void insert(const Comparable& x, AvlNodePtr& t) {
    if (!t) {
    t = new AvlNode(x, nullptr, nullptr);
    }
    else if (x < t->element) {
    insert(x, t->left);
    //比根结点小,插入左边 if (height(t->left) - height(t->right) == 2)//高度差达到2了 {
    if (x < t->left->element)//插入左边 {
    clockwiseRotate(t);
    //顺时针旋转 }
    else {
    doubleWithLeftChild(t);
    //双旋转 }
    }
    }
    else if (x > t->element) {
    insert(x, t->right);
    //比根结点大,插入右边 if (height(t->right) - height(t->left) == 2)//高度差达到2 {
    if (t->right->element < x)//插入右边 {
    antiClockWiseRotate(t);
    //旋转 }
    else {
    doubleWithRightChild(t);
    //双旋转 }
    }
    }
    else {
    //相同的 }
    t->height = max(height(t->left), height(t->right)) + 1;
    //计算结点的高度 }
    void removeMin(AvlNodePtr& x, AvlNodePtr& t)const {
    if (!t) {
    return;
    //找不到 }
    if (t->left) {
    removeMin(t->left);
    //使用了递归的方式 }
    else {
    //找到最小的结点了 x->element = t->element;
    AvlNodePtr oldNode = t;
    t = t->right;
    delete oldNode;
    //删除原来要删除的结点 }
    if (t) {
    t->height = max(height(t->left), height(t->right)) + 1;
    //计算结点的高度 if(height(t->left) - height(t->right) == 2) {
    //如果左儿子高度大于右儿子高度 if(height(t->left->left) >= height(t->left->right))//并且左儿子的左子树高度大于左儿子的右子树高度 {
    clockwiseRotate(t);
    //顺时针旋转 }
    else {
    doubleWithLeftChild(t);
    //双旋转左子树 }
    }
    else {
    if(height(t->right->right) - height(t->right->left) == 2) //如果右子树大于左子树 {
    antiClockWiseRotate(t);
    //逆时针旋转 }
    else {
    doubleWithRright(t);
    //双旋转右子树 }
    }
    }
    }
    //删除某个对象,这里必须要引用 void remove(const Comparable& x, AvlNodePtr& t)const {
    if (!t) {
    return;
    //树为空 }
    else if (x < t->element) {
    remove(x, t->left);
    //比根结点小,去左边查找 }
    else if (x > t->element) {
    remove(x, t->right);
    //比根结点大,去右边查找 }
    else if (!t->left && !t->right)//找到结点了,有两个叶子 {
    removeMin(t, t->right);
    //这里选择的方法是删除右子树的最小的结点 }
    else {
    AvlNodePtr oldNode = t;
    t = (t->left) ? t->left : t->right;
    //走到这里,t最多只有一个叶子,将t指向这个叶子 delete oldNode;
    //删除原来要删除的结点 }
    if (t) {
    t->height = max(height(t->left), height(t->right)) + 1;
    //计算结点的高度 if(height(t->left) - height(t->right) == 2) {
    //如果左儿子高度大于右儿子高度 if(height(t->left->left) >= height(t->left->right))//并且左儿子的左子树高度大于左儿子的右子树高度 {
    clockwiseRotate(t);
    //顺时针旋转 }
    else {
    doubleWithLeftChild(t);
    //双旋转左子树 }
    }
    else {
    if(height(t->right->right) - height(t->right->left) == 2) //如果右子树大于左子树 {
    antiClockWiseRotate(t);
    //逆时针旋转 }
    else {
    doubleWithRright(t);
    //双旋转右子树 }
    }
    }
    }
    //左边子树的结点肯定比当前根小的,所以一直往左边寻找 AvlNodePtr findMin(AvlNodePtr t)const {
    if (!t) {
    return nullptr;
    //找不到 }
    if (!t->left) {
    return t;
    }
    return findMin(t->left);
    //使用了递归的方式 }
    //右边子树的结点肯定比当前根大,所以一直往右边找 AvlNodePtr findMax(AvlNodePtr t)const {
    if (t) {
    while (t->right)//使用了循环的方式 {
    t = t->right;
    }
    }
    return t;
    }
    //判断是否包含某个对象,因为要使用递归,所以还有一个public版本的 bool contains(const Comparable& x, AvlNodePtr t)const {
    if (!t) {
    return false;
    //空结点了 }
    else if (x < t->element) {
    //根据二叉树的定义,比某个结点小的对象,肯定只能存在与这个结点的左边的子树 return contains(x, t->left);
    }
    else if (x > t->element) {
    //根据二叉树的定义,比某个结点大的对象,肯定只能存在与这个结点的右边的子树 return contains(x, t->right);
    }
    else {
    //相等,就是找到啦。 return true;
    }
    }
    //清空子树 void makeEmpty(AvlNodePtr& t) {
    if (t) {
    makeEmpty(t->left);
    //清空左边 makeEmpty(t->right);
    //清空右边 delete t;
    //释放自身 }
    t = nullptr;
    //置为空 }
    //打印子树,这里没有使用复杂的排位,纯属打印 void printTree(AvlNodePtr t)const {
    if (!t) {
    return;
    }
    std::cout << t->element << std::endl;
    //输出自身的对象 printTree(t->left);
    //打印左子树 printTree(t->right);
    //打印右子树 }
    AvlNodePtr clone(AvlNodePtr t)const {
    if (!t) {
    return nullptr;
    }
    return new AvlNode(t->element, clone(t->left), clone(t->right));
    }
    int height(AvlNodePtr t)const {
    return t == nullptr ? -1 : t->height;
    }
    }
    ;
    }
    #endif

简单测试一下。

    //// AvlTree.cpp// HelloWorld// Created by feiyin001 on 17/1/9.// Copyright (c) 2017年 FableGame. All rights reserved.//#include "AvlTree.h"using namespace Fable;
    int main(int argc, char* argv[]){
    AvlTree<int> a;
    for(int i = 0;
    i < 100;
    ++i) {
    a.insert(i);
    }
    return 0;
    }

这个删除的方法完全是自己写的,可能不是很高效。

希望本文所述对大家C语言程序设计有所帮助。

您可能感兴趣的文章:

  • 使用C语言构建基本的二叉树数据结构
  • 举例讲解C语言程序中对二叉树数据结构的各种遍历方式
  • C语言 数据结构平衡二叉树实例详解
  • C语言 数据结构之中序二叉树实例详解
  • C语言数据结构之线索二叉树及其遍历
  • C语言数据结构二叉树简单应用
  • C语言数据结构之二叉树的非递归后序遍历算法
  • C语言实现二叉树遍历的迭代算法
  • C语言 二叉树的链式存储实例
  • C语言二叉树的非递归遍历实例分析
  • C语言实现找出二叉树中某个值的所有路径的方法
相关热词搜索: C语言 数据结构 平衡二叉树 AVL树