A. DS查找—二叉树平衡因子
题目描述
二叉树用数组存储,将二叉树的结点数据依次自上而下,自左至右存储到数组中,一般二叉树与完全二叉树对比,比完全二叉树缺少的结点在数组中用0来表示。
计算二叉树每个结点的平衡因子,并按后序遍历的顺序输出结点的平衡因子。
--程序要求--
若使用C++只能include一个头文件iostream;若使用C语言只能include一个头文件stdio
程序中若include多过一个头文件,不看代码,作0分处理
不允许使用第三方对象或函数实现本题的要求
输入
测试次数t
每组测试数据一行,数组元素个数n,后跟n个字符,二叉树的数组存储。
2
6 ABC00D
24 ABCD0EF0000H00000000000I
输出
对每组测试数据,按后序遍历的顺序输出树中结点的平衡因子(测试数据没有空树)
B 0
D 0
C 1
A -1
D 0
B 1
I 0
H 1
E 2
F 0
C 2
A -2
#include <iostream>
using namespace std;
int max(int a, int b)
{
if (a > b)return a;
else return b;
}
void display(int i, char* array, int* b)//递归
{
if (array[2 * i] != '0')
{
display(2 * i, array, b);
}
if (array[2 * i + 1] != '0')
{
display(2 * i + 1, array, b);
}
cout << array[i] << " " << b[i] << endl;//后序遍历,左子树后右子树,之后输出
}
int main()
{
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
char* array = new char[1000];//初始值都先赋值为零
for (int i = 0; i < 1000; i++)
{
array[i] = '0';
}
int* balance = new int[1000];
int* depth = new int[1000];
for (int i = 0; i < 1000; i++)
{
balance[i] = depth[i] = 0;
}
for (int i = 1; i <= n; i++)
{
cin >> array[i];
}
for (int i = n; i >= 1; i--)//从后往前进行高度的计算
{
if (array[i] == '0')depth[i] = 0;
else depth[i] = max(depth[2 * i], depth[2 * i + 1]) + 1;
}
for (int i = 1; i <= n; i++)
{
balance[i] = depth[2 * i] - depth[2 * i + 1];//平衡因子的计算,左子树高度-右子树高度
}
display(1, array, balance);//递归
}
}
//平衡因子,字面意思,其实就是探讨左右是否平衡,如果不是,那么其中差了多少。
//然后规定了使用左子树的高度-右子树的高度=平衡因子,仅此而已!
//深度和高度在平衡二叉树中的区别就是,判断是否为平衡二叉树一般说深度,计算平衡因子一般说高度
B. DS二叉平衡树构建
题目描述
在初始为空的平衡二叉树中依次插入n个结点,请输出最终的平衡二叉树。
要求实现平衡二叉树,不可以使用各类库函数。
#include <iostream>
using namespace std;
#define LH 1 // 左高
#define EH 0 // 等高
#define RH -1 // 右高
class BiNode
{
public:
int key; // 关键值
int bf; // 平衡因子
BiNode *lChild, *rChild;
BiNode(int kValue, int bValue)
{
key = kValue;
bf = bValue;
lChild = NULL;
rChild = NULL;
}
~BiNode()
{
key = 0;
bf = 0;
lChild = NULL;
rChild = NULL;
}
};
// 二叉排序树
class BST
{
private:
BiNode *root; // 根结点指针
void rRotate(BiNode *&p);
void lRotate(BiNode *&p);
void leftBalance(BiNode *&t);
void rightBalance(BiNode *&t);
int insertAVL(BiNode *&t, int key, bool &taller); // 插入元素并做平衡处理
void inOrder(BiNode *p);
public:
BST();
void insertAVL(int key); // 二叉排序树插入元素
~BST();
void inOrder(); // 中序遍历
};
// 以p为根的二叉排序树作右旋处理
void BST::rRotate(BiNode *&p)
{
// 参考课本236页算法9.9
}
// 以p为根的二叉排序树作左旋处理
void BST::lRotate(BiNode *&p)
{
// 参考课本236页算法9.10
}
// t为根的二叉排序树作左平衡旋转处理
void BST::leftBalance(BiNode *&t)
{
// 参考课本238页算法9.12
}
// t为根的二叉排序树作右平衡旋转处理
void BST::rightBalance(BiNode *&t)
{
// 参考课本238页算法9.12
}
int BST::insertAVL(BiNode *&t, int key, bool &taller)
{
// 参考课本237页算法9.11
}
void BST::inOrder(BiNode *p)
{
if(p)
{
inOrder(p->lChild);
cout << p->key << ':' << p->bf << ' ';
inOrder(p->rChild);
}
return;
}
// 二叉排序树初始化
BST::BST()
{
root = NULL;
}
BST::~BST()
{
root = NULL;
}
// 插入元素并作平衡处理
void BST::insertAVL(int key)
{
bool taller = false;
insertAVL(root, key, taller);
}
// 中序遍历
void BST::inOrder()
{
inOrder(root);
}
int main(void)
{
int t;
cin >> t;
while(t --)
{
// 构建二叉平衡树,并在插入元素时做平衡处理
int n, elem;
cin >> n;
BST tree;
while(n --)
{
cin >> elem;
tree.insertAVL(elem);
}
tree.inOrder();
cout << endl;
}
return 0;
}
输入
第一行输入测试数据组数t;
每组测试数据,第一行输入结点数n, 第二行输入n个结点值。
8
3
64 5 1
3
64 5 13
6
64 78 5 1 13 15
6
64 78 5 1 13 10
3
64 78 100
3
64 80 70
6
64 30 80 90 70 68
6
64 30 80 90 70 75
输出
对每组测试数据,按中序遍历的顺序输出树中,结点值及平衡因子(测试数据没有空树),即结点值:平衡因子,不同结点之间间隔一个空格。
1:0 5:0 64:0
5:0 13:0 64:0
1:0 5:1 13:0 15:0 64:0 78:0
1:0 5:0 10:0 13:0 64:-1 78:0
64:0 78:0 100:0
64:0 70:0 80:0
30:0 64:0 68:0 70:0 80:-1 90:0
30:0 64:1 70:0 75:0 80:0 90:0
这道题纯粹的考察平衡二叉树的算法,非常纯粹,只需要照抄书上代码即可,但是同样有几点是需要注意的。
第一点是:输入输出问题,这题居然卡输出,main代码都给好了,居然卡输出,真是无语,但是我将中序遍历输入的那堆东西存到数组里面去了,分别是a数组和b数组,所以最后是用数组进行输出便于格式正确。
第二点是insertavl函数里太多弯弯绕绕了,容易看花眼,所以一定要小心检查。
第三点是insertavl函数里有个new t,注意看清楚自己的构造函数不要再傻傻的new了
#include <iostream>
using namespace std;
#define LH +1 // 左高
#define EH 0 // 等高
#define RH -1 // 右高
int a[1000];
int b[1000];
int z;
class BiNode
{
public:
int key; // 关键值
int bf; // 平衡因子
BiNode* lChild, * rChild;
BiNode(int kValue, int bValue)
{
key = kValue;
bf = bValue;
lChild = NULL;
rChild = NULL;
}
~BiNode()
{
key = 0;
bf = 0;
lChild = NULL;
rChild = NULL;
}
};
// 二叉排序树
class BST
{
private:
BiNode* root; // 根结点指针
void rRotate(BiNode*& p);
void lRotate(BiNode*& p);
void leftBalance(BiNode*& t);
void rightBalance(BiNode*& t);
int insertAVL(BiNode*& t, int key, bool& taller); // 插入元素并做平衡处理
void inOrder(BiNode* p);
public:
BST();
void insertAVL(int key); // 二叉排序树插入元素
~BST();
void inOrder(); // 中序遍历
};
// 以p为根的二叉排序树作右旋处理
void BST::rRotate(BiNode*& p)
{
// 参考课本236页算法9.9
BiNode* lc;//建立一个新的节点
lc = p->lChild;//lc指向的*p的左子树根节点
p->lChild = lc->rChild;//lc的左子树挂接为*p的左子树
lc->rChild = p;
p = lc;//p指向新的节点
}
// 以p为根的二叉排序树作左旋处理
void BST::lRotate(BiNode*& p)
{
// 参考课本236页算法9.10
BiNode* rc;
rc = p->rChild;//rc指向的*p的右子树根节点
p->rChild = rc->lChild;
rc->lChild = p;
p = rc;
}
// t为根的二叉排序树作左平衡旋转处理
void BST::leftBalance(BiNode*& t)
{
// 参考课本238页算法9.12
BiNode* lc;
lc = t->lChild;
switch (lc->bf)
{
case LH:
t->bf = lc->bf = EH;
rRotate(t);
break;
case RH:
BiNode* rd;
rd = lc->rChild;
switch (rd->bf)
{
case LH:
t->bf = RH;
lc->bf = EH;
break;
case EH:
t->bf = lc->bf = EH;
break;
case RH:
t->bf = EH;
lc->bf = LH;
break;
}
rd->bf = EH;
lRotate(t->lChild);
rRotate(t);
}
}
// t为根的二叉排序树作右平衡旋转处理
void BST::rightBalance(BiNode*& t)
{
// 参考课本238页算法9.12
//对指针T所致节点为根的二叉树作平衡旋转处理
BiNode* rc;
rc = t->rChild;
//检查T节点的右孩子,根据其平衡因子判断是左旋还是右左双旋
switch (rc->bf)
{
//右孩子的平衡因子为-1,平衡因子是直线,左旋
case RH:
t->bf = EH;
rc->bf = EH;
lRotate(t);
break;
//右孩子平衡因子为-1,平衡因子为折线,右左双旋
case LH:
BiNode* ld;
ld = rc->lChild;
//修改T节点和其右孩子的平衡因子
switch (ld->bf)
{
case LH:
t->bf = EH;
rc->bf = RH;
break;
case EH:
t->bf = rc->bf = EH;
break;
case RH:
t->bf = LH;
rc->bf = EH;
break;
}
ld->bf = EH;
rRotate(t->rChild);
lRotate(t);
}
}
int BST::insertAVL(BiNode*& t, int key, bool& taller)
{
// 参考课本237页算法9.11
if (!t)
{
t = new BiNode(key, EH);
taller = true;
}
else
{
if (t->key==key)
{
taller = false;
return 0;
}
if (key < t->key)
{
if (!insertAVL(t->lChild, key, taller)) {
taller = false;
return 0;
}
if (taller)
{
switch (t->bf)
{
case LH:
leftBalance(t);
taller = false;
break;
case EH:
t->bf = LH;
taller = true;
break;
case RH:
t->bf = EH;
taller = false;
break;
}
}
}
else
{
if (!insertAVL(t->rChild, key, taller))
{
taller = false;
return 0;
}
if (taller)
{
switch (t->bf)
{
case LH:
t->bf = EH;
taller = false;
break;
case EH:
t->bf = RH;
taller = true;
break;
case RH:
rightBalance(t);
taller = false;
break;
}
}
}
}
return 1;
}
void BST::inOrder(BiNode* p)
{
if (p)
{
inOrder(p->lChild);
//cout << p->key << ':' << p->bf << ' ';
a[z] = p->key;
b[z] = p->bf;
z++;
inOrder(p->rChild);
}
return;
}
// 二叉排序树初始化
BST::BST()
{
root = NULL;
}
BST::~BST()
{
root = NULL;
}
// 插入元素并作平衡处理
void BST::insertAVL(int key)
{
bool taller = false;
insertAVL(root, key, taller);
}
// 中序遍历
void BST::inOrder()
{
inOrder(root);
}
int main(void)
{
int t;
cin >> t;
while (t--)
{
// 构建二叉平衡树,并在插入元素时做平衡处理
int n, elem;
cin >> n;
BST tree;
int n1 = n;
while (n--)
{
cin >> elem;
tree.insertAVL(elem);
}
tree.inOrder();
for (int i = 0; i < n1; i++)
{
cout << a[i] << ":" << b[i];
if (i != n1 - 1)
cout << " ";
if(t)
cout << endl;
z = 0;
}
return 0;
}
C. 二叉平衡树练习
题目描述
对二叉平衡树进行四种操作:
1 D K
表示插入一个新数据,数据为D
用于输出,关键值为K
用于排序;2
输出当前树中最大关键值所带的数据,并删除该数据,如果没有这个关键值,则输出0
;3
输出当前树中最小关键值所带的数据,并删除该数据,如果没有这个关键值,则输出0
;4 K
输出关键值为K
的数据,并删除该数据,如果没有这个关键值,则输出0
。
要求必须实现平衡树,不可以使用各类库函数
AVL代码模板参考:
#include<stdio.h>
const int maxn = 1e5 + 10;
struct Node
{
int key; // 关键值
int data; // 携带的数据
int left; // 左子树地址(数组下标)
int right; // 右子树地址(数组下标)
int height; // 当前结点为根的子树高度
void Init(){data = key = left = right = height = -1;}
void Init(int k_, int d_=0){Init(); key = k_; data = d_;}
Node(){Init();}
Node(int k_, int d_=0){Init(k_, d_);}
};
Node tr[maxn];
int root, tp; // root标记根节点位置,tp全局结点分配下标
inline int UpdateHeight(int now)
{
// 更新 tr[now] 结点的子树高度,即tr[now].height的值
}
inline int HeightDiff(int now)
{
// 计算 tr[now] 结点的平衡因子
}
int LL(int an)
{
}
int RR(int an)
{
}
int LR(int an)
{
}
int RL(int an)
{
}
void Insert(int &now, int key, int data=0)
{
if(now == -1)
{
// 传入指针为空,新建结点保存数据
now = ++ tp;
tr[now].Init(key, data);
}
// 判断插入哪个子树,插入数据,判断平衡因子,做正确旋转,更新高度
}
void Delete(int &now, int key)
{
if(now == -1) return;
else if(key < tr[now].key) Delete(tr[now].left, key);
else if(key > tr[now].key) Delete(tr[now].right, key);
else
{
// 删除当前结点
}
// 处理树平衡
}
int main()
{
int n, op, key, data;
while(scanf("%d", &n) != EOF)
{
for(root = tp = -1; n --; ) // 初始化根结点和“内存指针”
{
scanf("%d", &op);
if(op == 1)
{
}
else if(op == 2)
{
}
else if(op == 3)
{
}
else
{
}
}
return 0;
}
输入
每组数据第一行n
表示有n
个操作
接下来n
行操作内容
8
2
1 20 14
1 30 3
2
1 10 99
3
2
2
输出
按操作规则输出对应内容
0
20
30
10
0
#include<iostream>
#include<cstdio>
#include <vector>
using namespace std;
int Max(int a, int b)
{
if (a<b)
{
return b;
}
else
{
return a;
}
}
const int maxn = 1e5 + 10;
struct Node
{
int key; // 关键值
int data; // 携带的数据
int left; // 左子树地址(数组下标)
int right; // 右子树地址(数组下标)
int height; // 当前结点为根的子树高度
void Init() { data = key = left = right = height = -1; }
void Init(int k_, int d_ = 0) { Init(); key = k_; data = d_; }
Node() { Init(); }
Node(int k_, int d_ = 0) { Init(k_, d_); }
};
Node tr[maxn];
int root, tp; // root标记根节点位置,tp全局结点分配下标
inline int UpdateHeight(int now)
{
// 更新 tr[now] 结点的子树高度,即tr[now].height的值
return tr[now].height = Max(tr[tr[now].left].height, tr[tr[now].right].height) + 1;
}
inline int HeightDiff(int now)
{
// 计算 tr[now] 结点的平衡因子
return tr[tr[now].left].height - tr[tr[now].right].height;
}
int LL(int an)
{
int bn = tr[an].left;
tr[an].left = tr[bn].right;
tr[bn].right = an;
UpdateHeight(an);
UpdateHeight(bn);
return bn;
}
int RR(int an)
{
int bn = tr[an].right;
tr[an].right = tr[bn].left;
tr[bn].left = an;
UpdateHeight(an);
UpdateHeight(bn);
return bn;
}
int LR(int an)
{
tr[an].left = RR(tr[an].left);
return LL(an);
}
int RL(int an)
{
tr[an].right = LL(tr[an].right);
return RR(an);
}
void Insert(int& now, int key, int data = 0)
{
if (now == -1)
{
// 传入指针为空,新建结点保存数据
now = ++tp;
tr[now].Init(key, data);
}
// 判断插入哪个子树,插入数据,判断平衡因子,做正确旋转,更新高度
else if (key < tr[now].key)
{
Insert(tr[now].left, key, data);
if (HeightDiff(now) == 2)
{
if (key < tr[tr[now].left].key) now = LL(now);
else now = LR(now);
}
}
else if (key > tr[now].key)
{
Insert(tr[now].right, key, data);
if (HeightDiff(now) == -2)
{
if (key > tr[tr[now].right].key) now = RR(now);
else now = RL(now);
}
}
UpdateHeight(now);
}
int FindMax(int now)
{
if (tr[now].right == 0)return -1;
while (tr[now].right != -1) now = tr[now].right;
return now;
}
int FindMin(int now)
{
if (tr[now].left == 0)return -1;
while (tr[now].left != -1) now = tr[now].left;
return now;
}
void Delete(int& now, int key)
{
if (now == -1) return;
else if (key < tr[now].key) Delete(tr[now].left, key);
else if (key > tr[now].key) Delete(tr[now].right, key);
else
{
// 删除当前结点
if (tr[now].left == -1 && tr[now].right == -1)
{
now = -1;
return;
}
else if (tr[now].left != -1 && tr[now].right == -1)
{
now = tr[now].left;
return;
}
else if (tr[now].left == -1 && tr[now].right != -1)
{
now = tr[now].right;
return;
}
else
{
int maxLeftIndex = FindMax(tr[now].left);
swap(tr[now].key, tr[maxLeftIndex].key);
swap(tr[now].data, tr[maxLeftIndex].data);
Delete(tr[now].left, tr[maxLeftIndex].key);
if (HeightDiff(now) == 2)
{
if (HeightDiff(tr[now].left) >= 0) now = LL(now);
else now = LR(now);
}
UpdateHeight(now);
}
}
// 处理树平衡
if (HeightDiff(now) == 2)
{
if (HeightDiff(tr[now].left) >= 0) now = LL(now);
else now = LR(now);
}
else if (HeightDiff(now) == -2)
{
if (HeightDiff(tr[now].right) <= 0) now = RR(now);
else now = RL(now);
}
UpdateHeight(now);
}
void InorderTraversal(int now, vector<int>& res)
{
if (now == -1) return;
InorderTraversal(tr[now].left, res);
res.push_back(tr[now].key);
InorderTraversal(tr[now].right, res);
}
int main()
{
int n, op, key, data;
while (scanf("%d", &n) != EOF)
{
for (root = tp = -1; n--; ) // 初始化根结点和“内存指针”
{
scanf("%d", &op);
if (op == 1)
{
scanf("%d%d", &data, &key);
Insert(root, key, data);
}
else if (op == 2)
{
int maxNodeIndex = FindMax(root);
if (maxNodeIndex == -1 || tr[maxNodeIndex].data < 0)
{
printf("0\n");
}
else
{
printf("%d\n", tr[maxNodeIndex].data);
Delete(root, tr[maxNodeIndex].key);
}
}
else if (op == 3)
{
int minNodeIndex = FindMin(root);
if (minNodeIndex == -1 || tr[minNodeIndex].data < 0)
{
printf("0\n");
}
else
{
printf("%d\n", tr[minNodeIndex].data);
Delete(root, tr[minNodeIndex].key);
}
}
else
{
scanf("%d", &key);
int nodeIndex = root;
while (nodeIndex != -1 && tr[nodeIndex].key != key)
{
if (tr[nodeIndex].key < key)
{
nodeIndex = tr[nodeIndex].right;
}
else
{
nodeIndex = tr[nodeIndex].left;
}
}
if (nodeIndex == -1 || tr[nodeIndex].data < 0)
{
printf("0\n");
}
else
{
printf("%d\n", tr[nodeIndex].data);
Delete(root, key);
}
}
}
}
return 0;
}
D. 平衡树上的第k小
题目描述
二种操作:
1 Key
表示插入一个新数据Key
;2 K
输出当前数据从小到大排列的第K
个数,并删除这个数,不存在则输出-1
。
要求使用平衡树实现
输入
每组数据第一行n
表示有n
个操作
接下来n
行操作内容
1 <= n <= 10^5
8
1 1
1 2
1 3
1 4
1 5
2 2
2 2
2 6
输出
按操作规则输出对应内容
2
3
-1
#include <iostream>
using namespace std;
struct TreeNode {
int key, height, size;
TreeNode *left, *right;
TreeNode(int k) : key(k), height(1), size(1), left(nullptr), right(nullptr) {}
};
int height(TreeNode *node) {
return node ? node->height : 0;
}
int balanceFactor(TreeNode *node) {
return height(node->right) - height(node->left);
}
void updateHeightAndSize(TreeNode *node) {
node->height = max(height(node->left), height(node->right)) + 1;
node->size = (node->left ? node->left->size : 0) + (node->right ? node->right->size : 0) + 1;
}
void rotateRight(TreeNode *&node) {
TreeNode *left = node->left;
node->left = left->right;
left->right = node;
updateHeightAndSize(node);
updateHeightAndSize(left);
node = left;
}
void rotateLeft(TreeNode *&node) {
TreeNode *right = node->right;
node->right = right->left;
right->left = node;
updateHeightAndSize(node);
updateHeightAndSize(right);
node = right;
}
void balance(TreeNode *&node) {
if (balanceFactor(node) == 2) {
if (balanceFactor(node->right) < 0) {
rotateRight(node->right);
}
rotateLeft(node);
} else if (balanceFactor(node) == -2) {
if (balanceFactor(node->left) > 0) {
rotateLeft(node->left);
}
rotateRight(node);
}
updateHeightAndSize(node);
}
void insert(TreeNode *&node, int key) {
if (!node) {
node = new TreeNode(key);
} else if (key < node->key) {
insert(node->left, key);
} else if (key > node->key) {
insert(node->right, key);
}
balance(node);
}
int getKth(TreeNode *&node, int k) {
int r = (node->left ? node->left->size : 0) + 1;
if (k == r) {
int res = node->key;
if (!node->left && !node->right) {
delete node;
node = nullptr;
} else if (node->left && !node->right) {
TreeNode *tmp = node;
node = node->left;
delete tmp;
} else if (!node->left && node->right) {
TreeNode *tmp = node;
node = node->right;
delete tmp;
} else {
TreeNode *p = node->right;
while (p->left) {
p = p->left;
}
node->key = p->key;
getKth(node->right, 1);
}
return res;
} else if (k < r) {
return getKth(node->left, k);
} else {
return getKth(node->right, k - r);
}
}
int main() {
int n;
cin >> n;
TreeNode *root = nullptr;
for (int i = 0; i < n; i++) {
int op, k;
cin >> op >> k;
if (op == 1) { // 插入操作
insert(root, k);
} else if (op == 2) { // 查找并删除第 k 小的元素
if (root && root->size >= k) {
cout << getKth(root, k) << endl;
} else {
cout << -1 << endl;
}
}
}
return 0;
}