二叉树
记录
21:16 2024-3-3
1. 二叉树
1.二叉查找树(BST)
先把自己当时学的时候写的放上来 reference:《数据结构与算法分析》
点击查看代码
#define _CRT_SECURE_NO_WARNINGS //vs中scanf为不安全的函数 要使用 得加上这句话
#include<stdio.h>
#include<malloc.h>
typedef struct TNode* BinTree;
typedef BinTree Position;
struct TNode
{
int Element;
BinTree Left;
BinTree Right;
};
BinTree Trees[10];
Position Find(int Element, BinTree BST);
Position FindMin(BinTree BST);
Position FindMax(BinTree BST);
BinTree Insert(int Element, BinTree BST);
BinTree Delete(int Element, BinTree BST);
/*Position Find(int Element, BinTree BST)
{
if (!BST) //查找失败
return NULL;
if (Element < BST->Element)
return Find(Element, BST->Left); //在左子树中查找
else if (BST->Element < Element)
return Find(Element, BST->Right); //在右子树中查找
else
return BST; //查找成功
}*/ //尾递归实现 尾递归可以转化为 循环实现
Position Find(int Element, BinTree BST)
{
while (BST)
{
if (Element < BST->Element)
BST = BST->Left;
else if (BST->Element < Element)
BST = BST->Right;
else
return BST;
}
return NULL;
}
Position FindMin(BinTree BST)
{
while (BST->Left)
{
BST = BST->Left;
}
return BST;
}
Position FindMax(BinTree BST)
{
while (BST->Right)
{
BST = BST->Right;
}
return BST;
}
BinTree Delete(int Element, BinTree BST)
{
Position Tmp;
if (!BST)printf("未找到该元素");
else if (Element < BST->Element)
BST->Left=Delete(Element, BST->Left); //向左查找
else if (BST->Element < Element)
BST->Right=Delete(Element, BST->Right); //向右查找
else //找到了要删除的元素 接下来对要删除的元素的种类进行判断
if (BST->Left && BST->Right) //左右都有子树 第三种情况
{
Tmp = FindMin(BST->Right);
BST->Element= Tmp->Element; //用右子树的最小元素 或 左子树的最大元素来代替 该元素
BST->Right=Delete(BST->Element, BST->Right);
} //讨论 前两种情况
else
{
Tmp = BST;
if (!BST->Left) //只有右孩子或无节点
BST = BST->Right;
else if (!BST->Right) //只有左孩子或无节点
BST = BST->Left;
free(Tmp);
}
return BST;
}
BinTree Insert(int Element, BinTree BST)
{
if (!BST) //BST为空 生成该节点 并且返回
{
BST = (Position)malloc(sizeof(TNode));
BST->Element = Element; BST->Left = NULL; BST->Right = NULL;
}
else
if (Element < BST->Element)
BST->Left = Insert(Element, BST->Left); //递归插入左子树
else if (BST->Element < Element)
BST->Right = Insert(Element, BST->Right); //递归插入右子树
return BST;
}
void MakeTrees(int N,int i)
{
int num;
scanf("%d", &num);
Trees[i] = (BinTree)malloc(sizeof(TNode));
Trees[i]->Element = num;
Trees[i]->Left = Trees[i]->Right = NULL;
for (int j = 0; j< N - 1; j++)
{
scanf("%d", &num);
Trees[i]=Insert(num, Trees[i]);
}
getchar();
}
int Charge(BinTree T, BinTree Tree)
{
if (T == NULL && Tree == NULL) //空树 一定相同
return 1;
if (T->Element != Tree->Element) //判断节点处元素是否相同
return 0;
else
return Charge(T->Left, Tree->Left) && Charge(T->Right, Tree->Right);
}
int main()
{
int N;
int L;
scanf("%d", &N);
while (N)
{
scanf("%d\n", &L);
for (int i = 0; i <= L; i++)
MakeTrees(N,i);
for (int i = 1; i <= L; i++)
if (Charge(Trees[0], Trees[i]))
printf("Yes\n");
else
printf("No\n");
scanf("%d", &N);
}
}
利用数组实现
点击查看代码
struct BST {
int l, r; // 左右子节点在数组中的下标
int val; // 节点关键码
} a[SIZE]; // 数组模拟链表
int tot, root, INF = 1<<30;
int New(int val) {
a[++tot].val = val;
return tot;
}
void Build() {
New(-INF), New(INF);
root = 1, a[1].r = 2;
}
int Get(int p, int val) {
if (p == 0) return 0; // 检索失败
if (val == a[p].val) return p; // 检索成功
return val < a[p].val ? Get(a[p].l, val) : Get(a[p].r, val);
}
void Insert(int &p, int val) {
if (p == 0) {
p = New(val); // 注意p是引用,其父节点的l或r值会被同时更新
return;
}
if (val == a[p].val) return;
if (val < a[p].val) Insert(a[p].l, val);
else Insert(a[p].r, val);
}
int GetNext(int val) {
int ans = 2; // a[2].val==INF
int p = root;
while (p) {
if (val == a[p].val) { // 检索成功
if (a[p].r > 0) { // 有右子树
p = a[p].r;
// 右子树上一直向左走
while (a[p].l > 0) p = a[p].l;
ans = p;
}
break;
}
// 每经过一个节点,都尝试更新后继
if (a[p].val > val && a[p].val < a[ans].val) ans = p;
p = val < a[p].val ? a[p].l : a[p].r;
}
return ans;
}
void Remove(int &p, int val) { // 从子树p中删除值为val的节点
if (p == 0) return;
if (val == a[p].val) { // 已经检索到值为val的节点
if (a[p].l == 0) { // 没有左子树
p = a[p].r; // 右子树代替p的位置,注意p是引用
}
else if (a[p].r == 0) { // 没有右子树
p = a[p].l; // 左子树代替p的位置,注意p是引用
}
else { // 既有左子树又有右子树
// 求后继节点
int next = a[p].r;
while (a[next].l > 0) next = a[next].l;
// next一定没有左子树,直接删除
Remove(a[p].r, a[next].val);
// 令节点next代替节点p的位置
a[next].l = a[p].l, a[next].r = a[p].r;
p = next; // 注意p是引用
}
return;
}
if (val < a[p].val) {
Remove(a[p].l, val);
} else {
Remove(a[p].r, val);
}
}
2.Treap
通过给每个节点增加权重,维护权值最大堆的方式来防止二叉树退化为链,给出随机数,不用像AVL比较严格的平衡了
点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int SIZE = 100010;
struct Treap {
int l, r; // 左右子节点在数组中的下标
int val, dat; // 节点关键码、权值
int cnt, size; // 副本数、子树大小
} a[SIZE]; // 数组模拟链表
int tot, root, n, INF = 0x7fffffff;
int New(int val) {
a[++tot].val = val;
a[tot].dat = rand();
a[tot].cnt = a[tot].size = 1;
return tot;
}
void Update(int p) {
a[p].size = a[a[p].l].size + a[a[p].r].size + a[p].cnt;
}
void Build() {
New(-INF), New(INF);
root = 1, a[1].r = 2;
Update(root);
}
int GetRankByVal(int p, int val) {
if (p == 0) return 0;
if (val == a[p].val) return a[a[p].l].size + 1;
if (val < a[p].val) return GetRankByVal(a[p].l, val);
return GetRankByVal(a[p].r, val) + a[a[p].l].size + a[p].cnt;
}
int GetValByRank(int p, int rank) {
if (p == 0) return INF;
if (a[a[p].l].size >= rank) return GetValByRank(a[p].l, rank);
if (a[a[p].l].size + a[p].cnt >= rank) return a[p].val;
return GetValByRank(a[p].r, rank - a[a[p].l].size - a[p].cnt);
}
void zig(int &p) {
int q = a[p].l;
a[p].l = a[q].r, a[q].r = p, p = q;
Update(a[p].r), Update(p);
}
void zag(int &p) {
int q = a[p].r;
a[p].r = a[q].l, a[q].l = p, p = q;
Update(a[p].l), Update(p);
}
void Insert(int &p, int val) {
if (p == 0) {
p = New(val);
return;
}
if (val == a[p].val) {
a[p].cnt++, Update(p);
return;
}
if (val < a[p].val) {
Insert(a[p].l, val);
if (a[p].dat < a[a[p].l].dat) zig(p); // 不满足堆性质,右旋
}
else {
Insert(a[p].r, val);
if (a[p].dat < a[a[p].r].dat) zag(p); // 不满足堆性质,左旋
}
Update(p);
}
int GetPre(int val) {
int ans = 1; // a[1].val==-INF
int p = root;
while (p) {
if (val == a[p].val) {
if (a[p].l > 0) {
p = a[p].l;
while (a[p].r > 0) p = a[p].r; // 左子树上一直向右走
ans = p;
}
break;
}
if (a[p].val < val && a[p].val > a[ans].val) ans = p;
p = val < a[p].val ? a[p].l : a[p].r;
}
return a[ans].val;
}
int GetNext(int val) {
int ans = 2; // a[2].val==INF
int p = root;
while (p) {
if (val == a[p].val) {
if (a[p].r > 0) {
p = a[p].r;
while (a[p].l > 0) p = a[p].l; // 右子树上一直向左走
ans = p;
}
break;
}
if (a[p].val > val && a[p].val < a[ans].val) ans = p;
p = val < a[p].val ? a[p].l : a[p].r;
}
return a[ans].val;
}
void Remove(int &p, int val) {
if (p == 0) return;
if (val == a[p].val) { // 检索到了val
if (a[p].cnt > 1) { // 有重复,减少副本数即可
a[p].cnt--, Update(p);
return;
}
if (a[p].l || a[p].r) { // 不是叶子节点,向下旋转
if (a[p].r == 0 || a[a[p].l].dat > a[a[p].r].dat)
zig(p), Remove(a[p].r, val);
else
zag(p), Remove(a[p].l, val);
Update(p);
}
else p = 0; // 叶子节点,删除
return;
}
val < a[p].val ? Remove(a[p].l, val) : Remove(a[p].r, val);
Update(p);
}
int main() {
Build();
cin >> n;
while (n--) {
int opt, x;
scanf("%d%d", &opt, &x);
switch (opt) {
case 1:
Insert(root, x);
break;
case 2:
Remove(root, x);
break;
case 3:
printf("%d\n", GetRankByVal(root, x) - 1);
break;
case 4:
printf("%d\n", GetValByRank(root, x + 1));
break;
case 5:
printf("%d\n", GetPre(x));
break;
case 6:
printf("%d\n", GetNext(x));
break;
}
}
}
3.平衡二叉树(AVL)
先把自己当时学的时候写的放上来 reference:《数据结构与算法分析c语言描述》
嘛,现在只能记得左旋右旋了(喝左旋哈哈哈)
点击查看代码
// c版本 环境是VS2017 等我看下数据结构与算法分析c++描述把它也写上来
#define _CRT_SECURE_NO_WARNINGS //vs中scanf为不安全的函数 要使用 得加上这句话
#include<stdio.h>
#include<malloc.h>
typedef struct TNode* BinTree;
typedef BinTree Position;
struct TNode
{
int Element;
BinTree Left;
BinTree Right;
int Heigth; //高度
};
int GetHeight(BinTree T)
{
if (!T)
return -1;
else
return T->Heigth;
}
int Max(int a, int b)
{
return (a > b) ? a : b;
}
BinTree NewNode(int Element)
{
BinTree T = (BinTree)malloc(sizeof(struct TNode));
T->Element = Element;
T->Left = NULL;
T->Right = NULL;
T->Heigth = 0;
return T;
}
BinTree SingleLeftRotation(BinTree T)
{
BinTree TL = T->Left;
T->Left = TL->Right;
TL->Right = T;
T->Heigth = Max(GetHeight(T->Left), GetHeight(T->Right)) + 1;
TL->Heigth = Max(GetHeight(TL->Left),T->Heigth)+1;
return TL;
}
BinTree SingleRightRotation(BinTree T)
{
BinTree TR = T->Right;
T->Right = TR->Left;
TR->Left = T;
T->Heigth = Max(GetHeight(T->Left),GetHeight(T->Right))+1;
TR->Heigth =Max(GetHeight(TR->Right),T->Heigth)+1;
return TR;
}
BinTree DoubleLeftRightRotation(BinTree T)
{ //先做一次右单旋 再做一次左单旋
T->Left = SingleRightRotation(T->Left);
return SingleLeftRotation(T);
}
BinTree DoubleRightLeftRotation(BinTree T)
{//先做一次左旋 再做一次右旋
T->Right = SingleLeftRotation(T->Right);
return SingleRightRotation(T);
}
BinTree Insert(int Element, BinTree BST)
{
if (!BST) //BST为空 生成该节点 并且返回
BST = NewNode(Element);
else if (Element < BST->Element)
{
BST->Left = Insert(Element, BST->Left); //递归插入左子树
if (GetHeight(BST->Left) - GetHeight(BST->Right) == 2) //判断是否需要进行旋转
if (Element < BST->Left->Element) //左单旋
BST=SingleLeftRotation(BST);
else
BST=DoubleLeftRightRotation(BST); //左-右双旋
}
else if (BST->Element < Element)
{
BST->Right = Insert(Element, BST->Right); //递归插入右子树
if (GetHeight(BST->Left) - GetHeight(BST->Right) == -2)
if (Element > BST->Right->Element) //右单旋
BST=SingleRightRotation(BST);
else
BST=DoubleRightLeftRotation(BST); //右-左双旋
}
BST->Heigth = Max(GetHeight(BST->Left), GetHeight(BST->Right)) + 1;
return BST;
}
BinTree MakeTree()
{
int N;
scanf("%d",&N);
int num;
scanf("%d", &num);
BinTree T = NewNode(num);
for (int i = 1; i < N; i++)
{
scanf("%d", &num);
T=Insert(num, T);
}
return T;
}
int main()
{
BinTree Root = MakeTree();
printf("%d", Root->Element);
}