二叉树

记录

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);
}

4.红黑树(red black tree)

posted @ 2024-03-03 21:40  57one  阅读(2)  评论(0编辑  收藏  举报