标签:技巧 search 主函数 arc ati 链式存储 平衡二叉树 内容 二叉搜索树
根据插入序列建立二叉平衡树并输出根结点,其实就是考察能否掌握建立二叉平衡树的过程。这题去年有写过,但是一直卡住了,这次终于写出来了,而且真的见识到了一些很精妙的操作,不管是调整还是插入过程。
An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; if at any time they differ by more than one, rebalancing is done to restore this property. Figures 1-4 illustrate the rotation rules.
Now given a sequence of insertions, you are supposed to tell the root of the resulting AVL tree.
Each input file contains one test case. For each case, the first line contains a positive integer N (≤20) which is the total number of keys to be inserted. Then N distinct integer keys are given in the next line. All the numbers in a line are separated by a space.
For each test case, print the root of the resulting AVL tree in one line.
5
88 70 61 96 120
70
7
88 70 61 96 120 90 65
88
emmmm...简单介绍一下平衡二叉树,它是这样一种二叉搜索树,任何一个结点的左右两个子树的高度差不超过1。平衡二叉树的目的是为了能达到最高的搜索效率。
调整过程就不介绍了...
然后就是建立平衡二叉树的过程。
建立平衡二叉树的过程主要以插入为主,插入过程和搜索二叉树的过程一致,但是在每次插入之后,都要加一个调整的步骤,因为每一次插入都可能使其失衡。建立完成后,输出根结点即可。
精妙的在代码部分。
#include<iostream>
using namespace std;
typedef struct Node{
int data;
struct Node* lchild;
struct Node* rchild;
} Node;
int myHeight(Node * t) {
if (t == NULL)
return 0;
else {
int l = myHeight(t->lchild);
int r = myHeight(t->rchild);
return (l > r ? l : r) + 1; //一定要加括号,注意优先级的问题
}
}
bool myIsBalance(Node *t) {
int l = myHeight(t->lchild);
int r = myHeight(t->rchild);
if (l - r <= 1 && l - r >= -1)
return true;
else
return false;
}
Node* LL(Node* root) {
Node *p = root->lchild;
root->lchild = p->rchild;
p->rchild = root;
return p; //返回新的根结点
}
Node* RR(Node* root) {
Node* p = root->rchild;
root->rchild = p->lchild;
p->lchild = root;
return p;
}
Node* LR(Node* root) {
root->lchild = RR(root->lchild);
return LL(root);
}
Node* RL(Node* root) {
root->rchild = LL(root->rchild);
return RR(root);
}
Node* myNewNode(int key) {
Node *p = new Node;
p->lchild = NULL;
p->rchild = NULL;
p->data = key;
return p;
}
void myInsert(Node *&t, int key) {
if (t == NULL)
t = myNewNode(key);
else {
if (key > t->data) {
myInsert(t->rchild, key);
if (myIsBalance(t) == false) {
if (key > t->rchild->data)
t = RR(t);
else
t = RL(t);
}
}
else {
myInsert(t->lchild, key);
if (myIsBalance(t) == false) {
if (key < t->lchild->data)
t = LL(t);
else
t = LR(t);
}
}
}
return;
}
int main() { //主函数
Node* tree = NULL;
int num;
cin >> num;
for (int i = 0; i < num; i++) { //逐个插入即可
int temp;
cin >> temp;
myInsert(tree, temp); //插入函数(包括调整)
}
cout << tree->data;
return 0;
}
最普通的链式存储
typedef struct Node{
int data;
struct Node* lchild;
struct Node* rchild;
} Node;
分别对应四种失衡情况:LL、LR、RR、RL。注意这里需要调整的是里插入结点最近的失衡结点,因为调整完这个之后,更远处失衡的结点也就变的平衡了。
实现过程有个小技巧,LL、RR是基本情况,而LR、RL则可以通过两种基本操作的组合实现,比如,对于LR情况,就可以先对失衡结点的左结点进行RR操作,再对失衡结点进行LL操作。
还有个更棒的小技巧,注意这里的调整过程,输入是待调整的结点的地址,返回值则是调整过后根结点地址,这样在执行调整过程时可以省下很多操作,避免指针错指带来的一些问题。
Node* LL(Node* root) {
Node *p = root->lchild;
root->lchild = p->rchild;
p->rchild = root;
return p; //返回新的根结点
}
Node* RR(Node* root) {
Node* p = root->rchild;
root->rchild = p->lchild;
p->lchild = root;
return p;
}
Node* LR(Node* root) {
root->lchild = RR(root->lchild);
return LL(root);
}
Node* RL(Node* root) {
root->rchild = LL(root->rchild);
return RR(root);
}
int myHeight(Node * t) {
if (t == NULL)
return 0;
else {
int l = myHeight(t->lchild);
int r = myHeight(t->rchild);
return (l > r ? l : r) + 1; //一定要加括号,注意优先级的问题
}
}
bool myIsBalance(Node *t) {
int l = myHeight(t->lchild);
int r = myHeight(t->rchild);
if (l - r <= 1 && l - r >= -1)
return true;
else
return false;
}
精妙的使用递归过程实现插入和调整的!
Node* myNewNode(int key) {
Node *p = new Node;
p->lchild = NULL;
p->rchild = NULL;
p->data = key;
return p;
}
void myInsert(Node *&t, int key) { //未曾设想的道路,精妙!
if (t == NULL) //基本情况(base case)
t = myNewNode(key);
else {
if (key > t->data) { //默认插在了右边,所以如果不平衡只需要考虑右边的情况即可,即RL、RR,下同
myInsert(t->rchild, key); //精妙的是,因为是递归插入的,所以最先被检查到的肯定是最靠近插入结点的,即最近失衡树
if (myIsBalance(t) == false) { //检查插入之后是否失衡
if (key > t->rchild->data)
//要么就是在右边的右边,不能用key == rchild->rchild->data判断,因为哪怕是最近失衡结点,也有可能离插入结点超过两层,这里选择使用大小判断正是利用了二叉搜索树的性质
t = RR(t); //因为这个赋值语句直接改变了t的指向,所以在传参时,必须要使用引用才行
else
t = RL(t);
}
}
else {
myInsert(t->lchild, key);
if (myIsBalance(t) == false) {
if (key < t->lchild->data)
t = LL(t);
else
t = LR(t);
}
}
}
return;
}
标签:技巧 search 主函数 arc ati 链式存储 平衡二叉树 内容 二叉搜索树
原文地址:https://www.cnblogs.com/Za-Ya-Hoo/p/12725387.html