AVL树C++实现(插入,删除,查找,清空,遍历操作)

AVL.h文件代码

#pragma once
#include<iostream>
#include<stack>

#include <assert.h>
using namespace std;
using namespace std;
template<class T>
struct AVLNode{
    T data;
    AVLNode<T>*left, *right;
    int bf;
    AVLNode() :left(NULL), right(NULL), bf(0) {}
    AVLNode(T d, AVLNode<T>*l=NULL,AVLNode<T>*r=NULL):data(d),left(l),right(r),bf(0){}
};
template<class T>
class AVLTree {
public:
    AVLTree():root(NULL){}
    ~AVLTree() {};
    AVLTree(T Ref):Refvalue(Ref),root(NULL){}
    bool insert(AVLNode<T>*&ptr, T&e1);
    bool Remove(AVLNode<T>*&ptr, T x);
    void RotateL(AVLNode<T>*&ptr);
    void RotateR(AVLNode<T>*&ptr);
    void PrintBinTree(AVLNode<T>*&t, int level);
    void RotateLR(AVLNode<T>*&ptr);
    void RotateRL(AVLNode<T>*&ptr);
    AVLNode<T>* search(const T x, AVLNode<T>*ptr);
    friend istream& operator>>(istream&, AVLTree<T>& Tree);
    friend ostream& operator<<(ostream&, AVLTree<T>&Tree);
    void Delete(AVLNode<T>*ptr);
    void output(AVLNode<T>*ptr, ostream&out);
    AVLNode<T>*root;
    T Refvalue;
private:

};
template<class T>
void AVLTree<T>::RotateL(AVLNode<T>*&ptr) {
    AVLNode<T>*subL = ptr;
    ptr = subL->right;
    subL->right = ptr->left;
    ptr->left = subL;
    ptr->bf = subL->bf = 0;
}
template<class T>
void AVLTree<T>::RotateR(AVLNode<T>*&ptr) {
    AVLNode<T>*subR = ptr;
    ptr = subR->left;
    subR->left = ptr->right;
    ptr->right = subR;
    ptr->bf = subR->bf = 0;
}
template<class T>
void AVLTree<T>::RotateLR(AVLNode<T>*&ptr) {
    AVLNode<T>*subR = ptr, *subL = subR->left;
    ptr = subL->right;
    subL->right = ptr->left;
    ptr->left = subL;
    if (ptr->bf <= 0)subL->bf = 0;
    else subL->bf = -1;
    subR->left = ptr->right;
    ptr->right = subR;
    if (ptr->bf == -1)subR->bf = 1;
    else subR->bf = 0;
    ptr->bf = 0;
}
template<class T>
void AVLTree<T>::RotateRL(AVLNode<T>*&ptr) {
    AVLNode<T>*subL = ptr, *subR = subL->right;
    ptr = subR->left;
    subR->left = ptr->right;
    ptr->right = subR;
    if (ptr->bf >= 0)subR->bf = 0;
    else subR->bf = 1;
    subL->right = ptr->left;
    ptr->left = subL;
    if (ptr->bf == 1)subL->bf = -1;
    else subL->bf = 0;
    ptr->bf = 0;
}
template<class T>
bool AVLTree<T>::insert(AVLNode<T>*&ptr, T&e1) {
    AVLNode<T>*pr = NULL, *p = ptr, *q; int d;
    stack<AVLNode<T>*>st;
    while (p!=NULL)
    {
        if (e1 == p->data) {
            cout << "存在,无法插入\n"; return false;
        }
        pr = p; st.push(pr);
        if (e1 < p->data)p = p->left;
        else p = p->right;
    }
    p = new AVLNode<T>(e1);
    if (p == NULL) { cout << "内存不足" << endl; exit(1); }
    if (pr == NULL) { ptr = p; return true; }//空树,根结点插入
    if (e1 < pr->data)pr->left = p;
    else pr->right = p;
    while (st.empty()==false)
    {
        pr = st.top();
        st.pop();
        if (p == pr->left)pr->bf--;
        else pr->bf++;
        if (pr->bf == 0)break;//case 1,平衡退出
        if (abs(pr->bf) == 1) {//case 2
            p = pr;//回溯
        }
        else {//case 3 |bf|==2
            d = (pr->bf < 0) ? -1 : 1;
            if (p->bf == d) {
                if (d == -1)RotateR(pr);
                else RotateL(pr);
            }
            else {
                if (d == -1)RotateLR(pr);
                else RotateRL(pr);
            }
            break;
        }
    }
    if (st.empty() == true)ptr = pr;
    else {
        q = st.top();
        if (q->data > pr->data)q->left = pr;
        else q->right = pr;
    }
    return true;
}
//template<class T>
istream& operator >>(istream& in, AVLTree<int>& Tree) {
    int item;
    in >> item;
    while (item!=Tree.Refvalue)
    {

        Tree.insert(Tree.root,item);
        in >> item;

    }
    return in;
}

//template<class T>
ostream& operator<<(  ostream&out, AVLTree<int>&Tree) {
    out << "中序遍历输出各个结点数值:" << endl;
    Tree.output(Tree.root,out);
    out << endl;
    return out;

}
template<class T>
void AVLTree<T>::output(AVLNode<T>*ptr, ostream&out) {
    if (ptr != NULL) {
        output(ptr->left, out);
        cout << ptr->data << " ";
        output(ptr->right, out);
    }
}
template<class T>
AVLNode<T>* AVLTree<T>::search(const T x, AVLNode<T>*ptr) {
    if (ptr == NULL)return NULL;
    else if (x < ptr->data)return search(x, ptr->left);
    else if (x > ptr->data)return search(x, ptr->right);
    else return ptr;
}

template<class T>
void AVLTree<T>::Delete(AVLNode<T>*ptr) {
    if (ptr != NULL){
        Delete(ptr->left);
        Delete(ptr->right);
        delete ptr;
    }

}

template <class T>
void AVLTree<T>::PrintBinTree(AVLNode<T>*&t, int level)
{
    if (t == NULL)return;
    PrintBinTree(t->right, level + 1);
    for (int i = 0; i < 4 * (level - 1); i++)cout << " ";
    cout << t->data << endl;
    PrintBinTree(t->left, level + 1);
}

template<class T>
bool  AVLTree<T>::Remove(AVLNode<T>*&t, T val)
{
    assert(t != nullptr);

    AVLNode<T> *tmp = t;
    AVLNode<T> *pre_tmp = nullptr;
    AVLNode<T> *ppre_tmp = nullptr;
    AVLNode<T> *it_tmp = nullptr;
    stack<AVLNode<T>*> st;
    int sign, lable;    //符号标记
    int flag = 0;       //子树标记,下文具体解释

    while (tmp != nullptr) {
        if (tmp->data == val)       //找到跳出循环
            break;

        pre_tmp = tmp;
        st.push(pre_tmp);

        if (tmp->data > val)
            tmp = tmp->left;
        else
            tmp = tmp->right;
    }

    if (tmp == nullptr)               //未找到,返回
        return false;
    else if (tmp->left!= nullptr && tmp->right != nullptr) {
        pre_tmp = tmp;               //将有两个孩子的节点转化为只有一个孩子的节点,方法是寻找它中序遍历的直接前驱或后继
        st.push(pre_tmp);

        it_tmp = tmp->left;
        while (it_tmp->right!= nullptr) {
            pre_tmp = it_tmp;
            st.push(pre_tmp);
            it_tmp = it_tmp->right;
        }
        tmp->data = it_tmp->data;      //覆盖要删除的节点
        tmp = it_tmp;                      //tmp指向要删除的节点,函数结束前会delete tmp
    }

    if (tmp->left!= nullptr) {        //这样的判断方式会导致删除一个节点下两个没有孩子节点的节点时,由于左孩子均为空,直接跳入else
        it_tmp = tmp->left;
    }
    else {
        it_tmp = tmp->right;
    }

    if (pre_tmp == nullptr)
        t = it_tmp;
    else {
        if (pre_tmp->left== tmp) {   //上面直接跳入else,但我们在此处加上flag,用来识别它到底是pre_tmp的左孩子还是右孩子。
            flag = 0;
            pre_tmp->left= it_tmp;
        }
        else {
            flag = 1;
            pre_tmp->right = it_tmp;
        }

        while (!st.empty()) {
            pre_tmp = st.top();
            st.pop();

            if (pre_tmp->left == it_tmp && flag == 0)//此处flag=0,防止pre_tmp的左孩子为空,右孩子同样为空,直接进入else
                pre_tmp->bf++;
            else
                pre_tmp->bf--;

            if (!st.empty())
            {
                ppre_tmp = st.top();
                if (ppre_tmp->left == pre_tmp)
                {
                    sign = -1;      //sign用来识别是祖父节点的左孩子还是右孩子,下文链接会用上
                    flag = 0;
                }
                else {
                    sign = 1;
                    flag = 1;
                }
            }
            else
                sign = 0;    //栈空,它的祖先节点不存在,pre_tmp即为根节点,但是这里也要写上,否则sign的值会遗留下来

            if (pre_tmp->bf == -1 || pre_tmp->bf == 1)
                break;           //已经平衡,直接跳出
            if (pre_tmp->bf != 0) {      //m_bf为+2/-2
                if (pre_tmp->bf < 0) {
                    lable = -1;          //lable表示父节点符号,下面会用来区分同号异号
                    it_tmp = pre_tmp->left;
                }
                else {
                    lable = 1;
                    it_tmp = pre_tmp->right;
                }

                if (it_tmp->bf == 0) {       //pre_tmp的较高子树的头节点m_bf为0
                    if (lable == -1) {
                        RotateR(pre_tmp);
                        pre_tmp->bf = 1;
                        pre_tmp->right->bf = -1;
                    }
                    else {
                        RotateL(pre_tmp);
                        pre_tmp->bf = -1;
                        pre_tmp->left->bf = 1;
                    }
                    break;           //直接跳出,并没有链接,需要下文写上链接
                }

                if (it_tmp->bf == lable) {       //同号
                    lable == 1 ? RotateL(pre_tmp) : RotateLR(pre_tmp);
                }
                else {                            //异号
                    lable == -1 ? RotateLR(pre_tmp): RotateRL(pre_tmp);
                }
                //sign == -1 ? ppre_tmp->left_child = pre_tmp                //不能写成这样,因为sign值可能为0,会直接进入后者
                //                      : ppre_tmp->right_child = pre_tmp;   //!!!!! sign maybe 0 ! not only1 or -1 !!! warning!
                if (sign == -1)
                    ppre_tmp->left = pre_tmp;
                else if (sign == 1)            //else if正确方式
                    ppre_tmp->right = pre_tmp;
            }
            it_tmp = pre_tmp;       //回溯
        }
        if (st.empty())              //栈为空,根节点
            t = pre_tmp;
        else {             //这一段else参考书上没有,书是错的,如果不写此处,290break直接跳出while循环,会导致链接不上,数据丢失
            ppre_tmp = st.top();
            if (ppre_tmp->data > pre_tmp->data)
                ppre_tmp->left = pre_tmp;
            else
                ppre_tmp->right = pre_tmp;
        }
    }
    delete tmp;
    tmp = nullptr;
    return true;

}

源cpp代码

#include"AVL.h"
#include<iostream>
using namespace std;
int main()
{
    AVLTree<int> tree;
    cout << "建立AVL树,终止表示设为0" << endl;
    tree.Refvalue = 0;
    cout << "1:建树\n2:插入\n3:搜索\n4:删除\n5:输出\n6:清空\n7:退出\n";
    bool over = false;
    while (!over)
    {
        int c;
        int num;

        cin >> c;
        switch (c)
        {
    case 1: {
        cin >> tree;
        cout << "建树完毕\n";
        break;
    }
    case 2: {
        cin >> num; tree.insert(tree.root, num); cout << "插入完毕\n"; break; }
    case 3: {cin >> num; if (tree.search(num, tree.root) != NULL)cout << num << "已经被找到\n"; else cout << num << "不存在\n"; break; }
    case 4: {cin >> num; tree.Remove(tree.root, num); }
    case 5: {cout << tree; cout << " 凹凸打印AVL树\n"; tree.PrintBinTree(tree.root, 1); break; }
    case 6: {
        //tree.Delete(tree.root);
        tree.root=NULL;
        break; }
    case 7:{  over = true; break; }
        default:cout << "输入有误\n";
            break;
        }
    }

    char ch;
    cin >> ch;
}

原文地址:https://www.cnblogs.com/gzr2018/p/10112621.html

时间: 2024-11-02 22:59:56

AVL树C++实现(插入,删除,查找,清空,遍历操作)的相关文章

AVL树非递归插入删除思路

AVL树是最先发明的自平衡二叉查找树.在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树.查找.插入和删除在平均和最坏情况下都是O(log n).增加和删除可能需要通过一次或多次树旋转来重新平衡这个树.AVL树得名于它的发明者G.M. Adelson-Velsky和E.M. Landis,他们在1962年的论文<An algorithm for the organization of information>中发表了它. 节点的平衡因子是它的左子树的高度减去它的右子树的

顺序表 初始化 插入 删除 查找 合并 交换 判断为空 求长度

#include <stdio.h> #include <stdlib.h> #define OK 1 #define TRUE 1 #define ERROR -1 #define FALSE -1 #define OVERFLOW -2 #define ElemType int #define Status int typedef int ElemType typedef int Status #define LEN sizeof(SqList) #define MLC (Li

单链表 初始化 创建 头插法 尾插法 插入 删除 查找 合并 长度

#include <stdio.h> #include <stdlib.h> #define OK 1 #define ERROR -1 #define TRUE 1 #define FALSE -1 #define NULL 0 #define OVERFLOW -2 #define ElemType int #define Status int typedef int ElemType typedef int Status #define LEN sizeof(LNode) #

jQuery---jq操作标签文本(html(),text()),jq操作文档标签(插入,删除,修改),克隆,,jq操作属性,jq操作class属性,jq操作表单value,jq操作css,jq操作盒子(重要),jq操作滚动条

jQuery---jq操作标签文本(html(),text()),jq操作文档标签(插入,删除,修改),克隆,,jq操作属性,jq操作class属性,jq操作表单value,jq操作css,jq操作盒子(重要),jq操作滚动条 一丶jQ操作标签内文本 html() 标签元素中的内容 /** 替换的内容可以使一个js对象,jq对象,文本 **/ /* 获取值:获取选中标签元素的所有内容 ,包括标签*/ $('ul').html() " <li>1</li> <li&g

数据结构&amp;&amp;AVL树原理、插入操作详解及实现

1.基本概念 AVL树的复杂程度真是比二叉搜索树高了整整一个数量级--它的原理并不难弄懂,但要把它用代码实现出来还真的有点费脑筋.下面我们来看看: 2.AVL树是什么? AVL树本质上还是一棵二叉搜索树(因此读者可以看到我后面的代码是继承自二叉搜索树的),它的特点是: 1. 本身首先是一棵二叉搜索树. 2. 带有平衡条件:每个结点的左右子树的高度之差的绝对值(平衡因子)最多为1. 例如: 5              5 / \            / \ 2   6          2  

二叉查找树(插入、查找、遍历、删除.........)

[二叉查找树的性质] 二叉查找树是满足以下条件的二叉树: 左子树上的所有节点值均小于根节点值 右子树上的所有节点值均不小于根节点值 左右子树也都是二叉查找树 不存在两个节点的值相等 [二叉查找树的插入.删除过程] 二叉查找树的插入过程如下: 1. 若当前的二叉查找树为空,则插入的元素为根节点 2. 若插入的元素值小于根节点值,则将元素插入到左子树中:若插入的元素值不小于根节点值,则将元素插入到右子树中. 二叉查找树的删除,分三种情况进行处理: 1. p为叶子节点,直接删除该节点,再修改其父节点的

萌新笔记——C++里创建 Trie字典树(中文词典)(插入、查找、遍历、导入、导出)(上)

写了一个词典,用到了Trie字典树. 写这个词典的目的,一个是为了压缩一些数据,另一个是为了尝试搜索提示,就像在谷歌搜索的时候,打出某个关键字,会提示一串可能要搜索的东西. 首先放上最终的结果: input: 1 编程入门 2 编程软件 3 编程学习 4 编程学习网站 output: 1 char : 件 2 word : 编程软件 3 char : 习 4 word : 编程学习 5 char : 网 6 word : 编程学习网 7 char : 门 8 word : 编程入门 其实这里不应

ios 字符串的插入删除查找与替换,删除空格

NSString *str1 = @"This is a example.";  NSMutableString *mstr = [[NSMutableString alloc] init]; //创建可变字符串  NSRange substr; //子字符串的范围mstr = [NSMutableString stringWithString:str1];  //插入字符  [mstr insertString:@"very easy " atIndex:10];

[PHP] 数据结构-链表创建-插入-删除-查找的PHP实现

链表获取元素1.声明结点p指向链表第一个结点,j初始化1开始2.j<i,p指向下一结点,因为此时p是指向的p的next,因此不需要等于3.如果到末尾了,p还为null,就是没有查找到 插入元素1.插入元素和查找类似,找到位置后2.生成新的结点s, s->next=p->next p->next=s; 删除元素1.删除元素,找到位置后2.绕过一下,q=p->next p->next=q->next; <?php class Node{ public $data

链表 创建 插入 删除 查找 合并

最近学习了一下单链表的操作,将代码保存如下,供以后查看. 链表创建: 1.先建立一个不含数据的头指针*head,头指针的链接域为NULL. 2.声明一个用于暂存新申请空间的指针*pc,一个用于保存创建的链表的指针*r,令*r指向*head. 3.在循环中,为指针*pc申请空间,并给数据域赋值,head->next = pc, pc->next = NULL, head = pc. #define _CRT_SECURE_NO_DEPRECATE /*取消scanf,printf不安全之类的错误