二叉排序树和AVL树

二叉排序树和AVL树


引言:本文视频链接全部来自bilibili,因为是在bilibili大学上学qwq

一、二叉排序树

1. 理论定义
(1)、什么是二叉排序树

​ 二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树。是数据结构中的一类。在一般情况下,查询效率比链表结构要高。      —— 百度百科
 
完整定义请看:=> 二叉排序树

 

(2)、简单介绍二叉排序树

 
安利bilibili机智牛牛小嗨嗨关于平衡二叉树

 

2. 模拟画图

如何在纸上画出二叉排序树?
 

建议食用bilibiliCUIT金牛老师二叉排序树qwq

 

3. 要点分析

​   掌握规则后,新来的元素向左或是向右理解了以后,还需要考虑二叉树的两种储存方式,一是数组模拟的顺序存储,二是链式存储;这两种方式截然不同,都需要掌握。本文着重介绍链式存储,顺带提一下顺序存储。

​   新元素在插入过程中,它的值需要不断地与当前走到的节点值相比较,如果新元素值更大,就走向当前节点的左儿子(或称左子树)上,反之,走到当前节点的右儿子(或称右子树)上。那么怎么"走"呢?

设顺序存储数组为tree[N]

  1. 二叉排序树顺序存储:

    假设双亲结点下标为x,值记为p,

    即 p = tree[x];那么它的左儿子下标记为lc,右儿子下标记为rc,

    分两种情况

    1. 如果数组下标从0开始:那么有:

      lc = 2 * x + 1、rc = 2 * x + 2

    2. 如果数组下标从1开始:那么有:
      c = 2 * x、rc = 2 * x + 1

  2. 二叉排序树链式储存:

    链式寻找左右儿子直接用指针即可

4. 代码实现
(1)、定义结构体:
typedef struct Node
{
    int weight;
    struct Node* lc, * rc;
}node, * tree;

(2)、插入新节点:
void Insert(tree &T, int w)
{
    if (T == NULL) {
        T = new node;
        T->weight = w;
        T->lc = T->rc = NULL;
    } else {
        if (T->weight < w) Insert(T->rc, w);
        else Insert(T->lc, w);
    }
}
(3)、层序遍历:
void TierTravel(tree &T)
{
    queue <tree> q;
    q.push(T);
  
    while (!q.empty())
    {
        tree tmp = q.front(); q.pop();
        cout << tmp->weight << '\n';
        if (tmp->lc != NULL) q.push(tmp->lc);
        if (tmp->rc != NULL) q.push(tmp->rc);
    }
}
(4)、中序遍历:中序遍历二叉排序树可得到有序序列
void InOrderTravel(tree &T)
{
    if (T)
    {
        InOrderTravel(T->lc);
        cout << T->weight << '\n';
        InOrderTravel(T->rc);
    }
}
(5)、完整代码:

1、链式:

#include <iostream>
#include <cstdlib>
#include <queue>

using namespace std;

typedef struct Node
{
    int weight;
    struct Node* lc, * rc;
}node, * tree;

void Insert(tree &T, int w)
{
    if (T == NULL) 
    {
        T = new node;
        T->weight = w;
        T->lc = T->rc = NULL;
    } 
    else 
    {
        if (T->weight < w) Insert(T->rc, w);
        else Insert(T->lc, w);
    }
}

void InOrderTravel(tree &T)
{
    if (T)
    {
        InOrderTravel(T->lc);
        cout << T->weight << '\n';
        InOrderTravel(T->rc);
    }
}
int n, w;
int main()
{
    tree T = NULL;
    cin >> n;//共有n个数
    srand((unsigned)time(NULL));
    for (int i = 0; i < n; ++ i) 
    {
        cin >> w;
        Insert(T, w);
    }
    InOrderTravel(T);//测试,因为二叉排序树中序遍历可得到有序序列
    
    system("pause");
    
    return 0;
}

2、顺序:

#include <iostream>

using namespace std;

const int N = 100010;
int tree[2*N];

void Insert(int loc, int x)
{
    if(!tree[loc]) tree[loc] = x;
    else 
    {
        if (tree[loc] >= x) Insert(loc * 2 + 1, x);
        else Insert(loc * 2 + 2, x);
    }
}

void Inorder(int loc)
{
    if (!tree[loc]) return;
    Inorder(loc * 2 + 1);
    cout << tree[loc] << ' ';
    Inorder(loc * 2 + 2);
}

int n, x;

int main()
{
    cin >> n;
    for (int i = 0; i < n; ++ i)
    {
        cin >> x;
        Insert(0, x);
    }
    Inorder(0);
  
    return 0;
}

二、AVL树

1. 理论定义

  在计算机科学中,AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为1,所以它也被称为高度平衡树。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。AVL树得名于它的发明者G. M. Adelson-Velsky和E. M. Landis,他们在1962年的论文《An algorithm for the organization of information》中发表了它。     ——百度百科
 

2. 模拟旋转

 
bilibili林语石AVL平衡调整
 

3. 代码实现
#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

typedef struct Node
{
    int weight, height;
    struct Node* lc, * rc;
}Tnode, * tree;

int Getheight(tree &T)
{
    if (!T) return 0;
    
    return T->height;
}

Tnode* LLInsert(Tnode * A)
{
	Tnode * B = A -> lc;
	A -> lc = B -> rc;
	B -> rc = A;
	A ->height = max(Getheight(A->lc),Getheight(A->rc)) +1;
	B ->height = max(Getheight(B->lc),A->height) +1;
	return B ;
}

Tnode* RRInsert(Tnode *A)
{
    Tnode *B = A -> rc;
    A -> rc = B -> lc;
    B -> lc = A ;
    A ->height = max(Getheight(A->lc),Getheight(A->rc))+1;
    B ->height = max(Getheight(B->lc),Getheight(B->rc))+1;
    return B;
}

Tnode* LRInsert(Tnode *A)
{
    A->lc = RRInsert(A->lc);
    return LLInsert(A);
}

Tnode* RLInsert(Tnode *A)
{
    A -> rc = LLInsert(A->rc);
    return RRInsert(A);
}


Tnode * Insert(Tnode *T, int x)
{
	if(!T)
    {
		T = new Tnode;
		T -> weight = x;
		T -> lc = T -> rc = NULL;
	}
	else if(x < T->weight)
    {
		T -> lc = Insert(T -> lc, x);
		if(Getheight(T -> lc) - Getheight(T -> rc) == 2)
        {
			if(x < T -> lc ->weight) T = LLInsert(T);
			else T = LRInsert(T);

		}
	}
	else if(x > T->weight)
    {
		T -> rc = Insert(T -> rc, x);
		if(Getheight(T -> lc) - Getheight(T -> rc) == -2)
			if(x > T -> rc -> weight) T = RRInsert(T);
			else T = RLInsert(T);
	}

	T -> height = max(Getheight(T -> lc),Getheight(T -> rc)) + 1;

	return T;
}

void InOrderTravel(tree &T)
{
    if (T)
    {
        InOrderTravel(T->lc);
        cout << T->weight << '\n';
        InOrderTravel(T->rc);
    }
}
/*
void DFS(tree &T)
{
    if (!T) return;
    cout << T->weight << ' ';
    DFS(T->lc);
    DFS(T->rc);
}
*/
int n, w;

int main()
{
    tree T = NULL; 
    cin >> n;
    for (int i = 0; i < n; ++ i) 
    {
        cin >>w;
        T = Insert(T, w);
    }
    // DFS(T);
    InOrderTravel(T);
    
    system("pause");
    return 0;
}
/*
2 7 4 5 8 6
*/

如果后面有时间,会更新AVL树的删除操作

TO BE CONTINUE…

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值