SBTree的左旋右旋以及各种调整操作的基本实现(包含查找第k大的数值)

原创 2016年05月30日 12:37:38

在完成了左旋和右旋操作之后,我们要实现调用两种单旋操作的逻辑,也就是调整操作。

在插入之后,一共有 44 种触发旋转的情况,分别为 LL 型、LR 型、RR 型和 RL 型。

通过旋转的名称,可以很直观的想到其对应的不平衡的情况——比如 LR 型,就意味着左子树(L)的右子树(R)的元素个数过大。

还记得我们之前讲到过的,SBTree 的平衡条件么?一共有两个:

a: size[right[t]] ≥ max(size[left[left[t]]], size[right[left[t]]])
a:size[right[t]]≥max(size[left[left[t]]],size[right[left[t]]])

b: size[left[t]] ≥ max(size[left[right[t]]], size[right[right[t]]])
b:size[left[t]]≥max(size[left[right[t]]],size[right[right[t]]])

对于 LL 和 LR 型,违反了平衡条件 aa;对于 RR 和 RL 型,则违反了平衡条件 bb。

对应的,LL 型和 LR 型都一定能保证平衡条件 bb 的成立;RR 型和 RL 型也都能一定保证平衡条件 aa 的成立。

我们只需要检查其中一半的情况即可,来避免无谓的判断。我们可以将算法伪代码简化如下:

如果在处理左子树更高的情况:
LL 型:右旋 tt。
LR 型:左旋 tt 的左子树,再右旋 tt。
如果在处理右子树更高的情况:
RR 型:左旋 tt。
RL 型:右旋 tt 的右子树,再左旋 tt。
递归调整左子树其中左子树的左子树更高的情况
递归调整右子树其中右子树的右子树更高的情况
递归调整当前子树其中左子树更高的情况
递归调整当前子树其中右子树更高的情况
为什么可以不考虑右子树其中右子树的左子树更高的情况呢?因为这种情况在第 66 步已经被处理了。左子树其中左子树的右子树更高的情况也类似。因此我们可以通过和之前介绍的相比更简洁、高效的调整算法实现对 SBTree 的维护。

#include <iostream>

using namespace std;

class SBTNode {
public:
    int data, size, value;
    SBTNode * lchild, * rchild, * father;
    SBTNode(int init_data, int init_size = 0, SBTNode * init_father = NULL);
    ~SBTNode();

    void insert(int value);
    SBTNode * search(int value);
    SBTNode * predecessor();
    SBTNode * successor();
    void remove_node(SBTNode * delete_node);
    bool remove(int value);
    int select(int k);
};

class BinaryTree {
private:
    SBTNode * root;
public:
    BinaryTree();
    ~BinaryTree();
    void insert(int value);
    bool find(int value);
    bool remove(int value);
    int select(int k);
};

SBTNode ZERO(0);
SBTNode * ZPTR = &ZERO;

SBTNode::SBTNode(int init_data, int init_size, SBTNode * init_father) {
    data = init_data;
    size = init_size;
    lchild = ZPTR;
    rchild = ZPTR;
    father = init_father;
}

SBTNode::~SBTNode() {
    if (lchild != ZPTR) {
        delete lchild;
    }
    if (rchild != ZPTR) {
        delete rchild;
    }
}

SBTNode * left_rotate(SBTNode * node) {
    SBTNode * temp = node->rchild;
    node->rchild = temp->lchild;
    temp->lchild->father = node;
    temp->lchild = node;
    temp->father = node->father;
    node->father = temp;
    temp->size = node->size;
    node->size = node->lchild->size + node->rchild->size + 1;
    return temp;
}

SBTNode * right_rotate(SBTNode * node) {
    SBTNode * temp = node->lchild;
    node->lchild = temp->rchild;
    temp->rchild->father = node;
    temp->rchild = node;
    temp->father = node->father;
    node->father = temp;
    temp->size = node->size;
    node->size = node->lchild->size + node->rchild->size + 1;
    return temp;
}

SBTNode * maintain(SBTNode * node, bool flag) {
    if (flag == false) {
        if (node->lchild->lchild->size > node->rchild->size) {
            node = right_rotate(node);
        } else if (node->lchild->rchild->size > node->rchild->size) {
            node->lchild = left_rotate(node->lchild);
            node = right_rotate(node);
        } else {
            return node;
        }
    } else {
        if (node->rchild->rchild->size > node->lchild->size) {
            node = left_rotate(node);
        } else if (node->rchild->lchild->size > node->lchild->size) {
            node->rchild = right_rotate(node->rchild);
            node = left_rotate(node);
        } else {
            return node;
        }
    }
    node->lchild = maintain(node->lchild, false);
    node->rchild = maintain(node->rchild, true);
    node = maintain(node, false);
    node = maintain(node, true);
    return node;
}

SBTNode * insert(SBTNode * node, int value) {
    if (value == node->data) {
        return node;
    } else {
        node->size++;
        if (value > node->data) {
            if (node->rchild == ZPTR) {
                node->rchild = new SBTNode(value, 1, node);
            } else {
                node->rchild = insert(node->rchild, value);
            }
        } else {
            if (node->lchild == ZPTR) {
                node->lchild = new SBTNode(value, 1, node);
            } else {
                node->lchild = insert(node->lchild, value);
            }
        }
    }
    return maintain(node, value > node->data);
}

SBTNode * SBTNode::search(int value) {
    if (data == value) {
        return this;
    } else if (value > data) {
        if (rchild == ZPTR) {
            return ZPTR;
        } else {
            return rchild->search(value);
        }
    } else {
        if (lchild == ZPTR) {
            return ZPTR;
        } else {
            return lchild->search(value);
        }
    }
}

SBTNode * SBTNode::predecessor() {
    SBTNode * temp = lchild;
    while (temp != ZPTR && temp->rchild != ZPTR) {
        temp = temp->rchild;
    }
    return temp;
}

SBTNode * SBTNode::successor() {
    SBTNode * temp = rchild;
    while (temp != ZPTR && temp->lchild != ZPTR) {
        temp = temp->lchild;
    }
    return temp;
}

void SBTNode::remove_node(SBTNode * delete_node) {
    SBTNode * temp = ZPTR;
    if (delete_node->lchild != ZPTR) {
        temp = delete_node->lchild;
        temp->father = delete_node->father;
        delete_node->lchild = ZPTR;
    }

    if (delete_node->rchild != ZPTR) {
        temp = delete_node->rchild;
        temp->father = delete_node->father;
        delete_node->rchild = ZPTR;
    }
    if (delete_node->father->lchild == delete_node) {
        delete_node->father->lchild = temp;
    } else {
        delete_node->father->rchild = temp;
    }
    temp = delete_node;
    while (temp != NULL) {
        temp->size--;
        temp = temp->father;
    }
    delete delete_node;
}

bool SBTNode::remove(int value) {
    SBTNode * delete_node, * current_node;
    current_node = search(value);
    if (current_node == ZPTR) {
        return false;
    }
    size--;
    if (current_node->lchild != ZPTR) {
        delete_node = current_node->predecessor();
    } else if (current_node->rchild != ZPTR) {
        delete_node = current_node->successor();
    } else {
        delete_node = current_node;
    }
    current_node->data = delete_node->data;
    remove_node(delete_node);
    return true;
}

int SBTNode::select(int k) {
    int rank=lchild->size+1;
    if(rank==k){
     return data;   
    }
    else if(k<rank){
        return lchild->select(k);
    }else{
        return rchild->select(k-rank);   
    }
}

BinaryTree::BinaryTree() {
    root = NULL;
}

BinaryTree::~BinaryTree() {
    if (root != NULL) {
        delete root;
    }
}

void BinaryTree::insert(int value) {
    if (root == NULL) {
        root = new SBTNode(value, 1);
    } else {
        root = ::insert(root, value);
    }
}

bool BinaryTree::find(int value) {
    if (root->search(value) == NULL) {
        return false;
    } else {
       return true;
    }
}

bool BinaryTree::remove(int value) {
    return root->remove(value);
}

int BinaryTree::select(int k) {
    return root->select(k);
}

int main() {
    BinaryTree binarytree;
    int arr[10] = { 8, 9, 10, 3, 2, 1, 6, 4, 7, 5 };
    for (int i = 0; i < 10; i++) {
        binarytree.insert(arr[i]);
    }
    int k;
    cin >> k;
    cout << binarytree.select(k) << endl;
    return 0;
}
版权声明:ShirleyPaul原创,未经博主允许不得转载

avl树左旋右旋的理解

一直没搞懂非平衡二叉树变平衡二叉树时左旋右旋,今天下定决心搞懂,然后在众多博客中终于找到了这样一篇,非常形象,记录如下: AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树...
  • u012361418
  • u012361418
  • 2015年06月17日 16:32
  • 1946

二叉树的左旋和右旋

树的旋转,分为左旋和右旋,以下借助图来做形象的解释和介绍: 1.左旋(右子为轴,当前结点左旋) 如上图所示: 当在某个结点pivot上,做左旋操作时,我们假设它的右孩子y不是NIL[T],p...
  • tuhuolong
  • tuhuolong
  • 2011年10月05日 10:31
  • 7778

AVL树的旋转操作 图解 最详细

AVL树的旋转操作 图解 最详细 各大教课书上讲的都是左旋与右旋,其实这样很容易理解错误,我们换一种叫法。 我们称呼左旋为:逆进针旋转。 我们称呼右旋为:顺进针旋转。...
  • collonn
  • collonn
  • 2014年02月28日 11:47
  • 40897

树的左旋与右旋

下图所示操作称为对结点Q的右旋,对结点P的左旋。二者互为逆操作。 #include class BinTree{ private: typedef struct node{ ...
  • chuchus
  • chuchus
  • 2014年10月09日 16:47
  • 2039

平衡二叉树(AVL树)一图一步骤代码实现左旋右旋,左右平衡操作

/** * 类说明:AVL树 */ public class AVLTreeE extends ComparableE>> { NodeE> root; int size = ...
  • qq_35295155
  • qq_35295155
  • 2017年11月22日 10:36
  • 97

左旋字符串

题目要求:实现一个函数,可以左旋字符串中的k个字符。(右旋字符串同理) 例如:ABCDE左旋两个字符串得到CDEAB 代码如下(编译环境为VS2013): #define _CRT_SECUR...
  • qq_39412582
  • qq_39412582
  • 2018年02月01日 11:39
  • 41

红黑树的理解与学习&左旋与右旋操作

http://zh.wikipedia.org/wiki/%E7%BA%A2%E9%BB%91%E6%A0%91#.E7.94.A8.E9.80.94.E5.92.8C.E5.A5.BD.E5.A4....
  • fuqiaoyimeng
  • fuqiaoyimeng
  • 2014年10月08日 15:36
  • 978

二叉树左旋右旋

额,我又回来啦
  • bright_light_in_dark
  • bright_light_in_dark
  • 2016年05月14日 19:31
  • 1110

AVL树的左旋右旋理解

AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树。查找、插入和删除在平均和最坏情况下都是O(log n)。增加和删除可能需要通过一次或多...
  • gongweijiao
  • gongweijiao
  • 2012年11月22日 19:38
  • 3690

BFPRT算法查找第k大元素

线性查找算法,即从某n个元素中选取第k大(或者第k小)的元素,BFPRT算法可以保证在最坏的情况下仍然为线性时间复杂度O(n),该算法与快速排序及其相似, 在BFPTR算法中,仅仅是改变了快速排序Pa...
  • wuxiushu
  • wuxiushu
  • 2016年08月01日 11:38
  • 1020
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:SBTree的左旋右旋以及各种调整操作的基本实现(包含查找第k大的数值)
举报原因:
原因补充:

(最多只允许输入30个字)