size balanced tree

来源:互联网 发布:ubuntu chroot 编辑:程序博客网 时间:2024/05/17 21:56

一、性质

1. root->left.size >= MAX(root->right->left.size, root->right->right.size);

2. root->right.size >= MAX(root->left->left.size, root->left->right.size);

即:任意节点的子树大小不小于其兄弟节点的左右子树大小

二、实现

#pragma once#include<iostream>#define SAFE_TEST_RET(REALVALUE, TESTVALUE) if((REALVALUE) == (TESTVALUE)) return;#define SAFE_TEST_RET_VAL(REALVALUE, TESTVALUE, RETVALUE) if((RETVALUE) == (TESTVALUE)) return RETVALUE;class SBNode{public:SBNode():left(NULL), right(NULL), size(0), data(0){}public:SBNode* left;SBNode* right;int size;int data;};class SBTree{public:SBTree():root(NULL){}~SBTree(){}public:static void InsertNode(int data, SBNode* &pRoot){if (pRoot == NULL){pRoot = new SBNode;pRoot->data = data;pRoot->size = 1;}else{if (data < pRoot->data){InsertNode(data, pRoot->left);}else{InsertNode(data, pRoot->right);}pRoot->size += 1;MainTain(pRoot, data >= pRoot->data);}}static bool EraseNode(int key, SBNode* &pRoot){SAFE_TEST_RET_VAL(pRoot, NULL, false);if (key == pRoot->data){pRoot->size--;SBNode* pTmp;if (pRoot->left != NULL && pRoot->right == NULL){pTmp = pRoot;pRoot = pTmp->left;delete pTmp;}else if (pRoot->left == NULL && pRoot->right != NULL){pTmp = pRoot;pRoot = pRoot->right;delete pTmp;}else if (pRoot->left == NULL && pRoot->right == NULL){delete pRoot;pRoot = NULL;}else if (pRoot->left != NULL && pRoot->right != NULL){pTmp = pRoot->left;while(pTmp->right != NULL){pTmp = pTmp->right;}pRoot->data = pTmp->data;EraseNode(pTmp->data, pRoot->left);}return true;}else if (key < pRoot->data){if (EraseNode(key, pRoot->left)){pRoot->size--;}}else{if (EraseNode(key, pRoot->right)){pRoot->size--;}}}static SBNode* FindNode(int key, SBNode* pRoot){SAFE_TEST_RET_VAL(pRoot, NULL, NULL);if (key == pRoot->data){return pRoot;}else if (key < pRoot->data){return FindNode(key, pRoot->left);}elsereturn FindNode(key, pRoot->right);}static SBNode* SelectNode(int rank, SBNode* pRoot){SAFE_TEST_RET_VAL(pRoot, NULL, NULL);int curRank = SizeOf(pRoot->left) + 1;if (curRank == rank){return pRoot;}else{if (curRank < rank){return SelectNode(rank-curRank, pRoot->right);}elsereturn SelectNode(rank, pRoot->left);}}static int Rank(int key, SBNode* pRoot){SAFE_TEST_RET_VAL(pRoot, NULL, 0);if (pRoot->data == key){return SizeOf(pRoot->left)+1;}else if (key < pRoot->data){return Rank(key, pRoot->left);}elsereturn Rank(key, pRoot->right) + SizeOf(pRoot->left) + 1;}static void PrintNodes(SBNode* pRoot){SAFE_TEST_RET(pRoot, NULL);if (pRoot->left != NULL){PrintNodes(pRoot->left);}std::cout<<pRoot->data<<std::endl;if (pRoot->right != NULL){PrintNodes(pRoot->right);}}private:static int SizeOf(SBNode* pNode){SAFE_TEST_RET_VAL(pNode, NULL, 0);return pNode->size;}static void RightRotate(SBNode* &pNode){SAFE_TEST_RET(pNode, NULL);SBNode* pTop = pNode->left;pNode->left = pTop->right;pTop->right = pNode;pTop->size = pNode->size;pNode->size = SizeOf(pNode->left) + SizeOf(pNode->right) + 1;pNode = pTop;}static void LeftRotate(SBNode* &pNode){SAFE_TEST_RET(pNode, NULL);SBNode* pTop = pNode->right;pNode->right = pTop->left;pTop->left = pNode;pTop->size = pNode->size;pNode->size = SizeOf(pNode->left) + SizeOf(pNode->right) + 1;pNode = pTop;}static void MainTain(SBNode* &pNode, bool rightDeeper){SAFE_TEST_RET(pNode, NULL);if (!rightDeeper){SAFE_TEST_RET(pNode->left, NULL);if (SizeOf(pNode->left->left) > SizeOf(pNode->right)){RightRotate(pNode);}else if (SizeOf(pNode->left->right) > SizeOf(pNode->right)){LeftRotate(pNode->left);RightRotate(pNode);}elsereturn;}else{SAFE_TEST_RET(pNode->right, NULL);if (SizeOf(pNode->right->right) > SizeOf(pNode->left)){LeftRotate(pNode);}else if (SizeOf(pNode->right->left) > SizeOf(pNode->left)){RightRotate(pNode->right);LeftRotate(pNode);}elsereturn;}MainTain(pNode->left, false);MainTain(pNode->right, true);MainTain(pNode, true);MainTain(pNode, false);}public:SBNode* root;};


三、心得

相比其他平衡二叉树,SBT使用size作为旋转标记,可以在O(logn)的时间复杂度内获得rank等,用来搞排行榜正合适。实测顺序插入100W个节点(0~999999),与std::set对比,set需要9秒,SBT4秒。


0 0
原创粉丝点击