平衡二叉樹總結四:替罪羊樹(scapegoat tree)
之前在查treap樹的時候,偶然在知乎看到一篇比treap樹還簡單的替罪羊樹的介紹,傳送門:https://zhuanlan.zhihu.com/p/21263304,大神還是寫的很好的,有興趣的可以去看下,當然也可以看我的總結。
一 、平衡條件
左子樹大小 < alpha * 根大小 並且 右子樹大小 < alpha * 根大小
二、 替罪羊樹總結起來就兩個操作:
1.拉平,當樹不滿足平衡條件時,把樹伸展成連結串列。
2.重構,遞迴的選取連結串列的中點作為根節點重建平衡樹,這樣得到的幾乎是完美的平衡二叉樹。
三、基本操作
0.結構
struct scapegoat{ scapegoat* left; scapegoat* right; int val,size; bool real; scapegoat(int v,int s,bool r):val(v),size(s),real(r){left = right = NULL;} };
1.插入
先正常的插入到二叉搜尋樹中,再回溯的過程中,判斷是否違背了平衡條件,如果違背了,拉平並重構該樹。
tree insert(tree t,int val){ if(t==NULL){ t = new scapegoat(val,1,1); return t; } bool r = 0;(t->size)++; if(val > t->val){ t->right = insert(t->right,val); if(t->right->size > alpha*t->size+10){r=1;} } else if(val < t->val){ t->left = insert(t->left,val); if(t->left->size > alpha*t->size+10){r=1;} } if(r){ qu.clear();tree2list(t); t = rebuild(0,qu.size()-1); } return t; }
2.刪除
採用lazy刪除,刪除的給打上一個標記,每次重構都把lazy點刪掉。
bool remove(tree t,int val){ if(t==NULL)return 0; bool c; if(val>t->val)c = remove(t->right,val); else if(val<t->val)c = remove(t->left,val); else{ if(t->real){t->real=0;c=1;} else{c=0;} } if(c)(t->size)--; return c; }
3.總結
總體來說思想很簡單,不過程式設計還是有一定複雜度的,更treap樹差不太多,效能的話據說是平均O(log(n))的,不過我的程式碼貌似重構的很頻繁,不知道是不是寫錯了。
現在研究的不深,之後有機會再補充。
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
struct scapegoat{
scapegoat* left;
scapegoat* right;
int val,size;//值域與儲存真實點個數的size域
bool real;//該點是否是真實的
scapegoat(int v,int s,bool r):val(v),size(s),real(r){left = right = NULL;}
};
typedef scapegoat* tree;
const int alpha = 0.55;//權重因子
vector<tree> qu;
void tree2list(tree t){//拉平樹
if(t==NULL)return;
if(t->left)tree2list(t->left);
if(t->real)qu.push_back(t);
if(t->right)tree2list(t->right);
if(!t->real)delete t;
}
tree rebuild(int left,int right){//重構樹
if(left > right)return NULL;
int m = (left+right)/2;
tree t = qu[m];
t->size = right-left+1;
t->left = rebuild(left,m-1);
t->right = rebuild(m+1,right);
return t;
}
tree insert(tree t,int val){
if(t==NULL){
t = new scapegoat(val,1,1);
return t;
}
bool r = 0;(t->size)++;
if(val > t->val){
t->right = insert(t->right,val);
if(t->right->size > alpha*t->size+10){r=1;}
}
else if(val < t->val){
t->left = insert(t->left,val);
if(t->left->size > alpha*t->size+10){r=1;}
}
if(r){
cout << "dd" <<endl;
qu.clear();tree2list(t);
t = rebuild(0,qu.size()-1);
}
return t;
}
bool remove(tree t,int val){
if(t==NULL)return 0;
bool c;
if(val>t->val)c = remove(t->right,val);
else if(val<t->val)c = remove(t->left,val);
else{
if(t->real){t->real=0;c=1;}
else{c=0;}
}
if(c)(t->size)--;
return c;
}
void level(tree t){
if(!t)return;
tree now,last=t;
queue<tree> qu1;
qu1.push(t);
while(qu1.size()){
now = qu1.front();qu1.pop();
if(now->left)qu1.push(now->left);
if(now->right)qu1.push(now->right);
cout << now->val << "(" << now->size << ")" << " ";
if(now == last && qu1.size()){last = qu1.back();cout << endl;}
}
cout << endl;
}
int main(){
int i;
tree t=NULL;
for(i=0;i<100;i++){
t = insert(t,i);
}
level(t);
}
相關推薦
平衡二叉樹總結四:替罪羊樹(scapegoat tree)
之前在查treap樹的時候,偶然在知乎看到一篇比treap樹還簡單的替罪羊樹的介紹,傳送門:https://zhuanlan.zhihu.com/p/21263304,大神還是寫的很好的,有興趣的可以去看下,當然也可以看我的總結。 一 、平衡條件 左子樹大小 <
平衡二叉樹總結三:treap樹(樹堆)
類似avl樹的還有紅黑樹和伸展樹,然而程式設計確實很複雜,我先總結treap樹吧,比賽啥的也能用得上。從樹堆這個名字不難看出treap這種資料結構應該同時具有二叉搜尋樹與二叉堆的某些性質,實際上樹堆首先是一顆二叉搜尋樹,也就是說它滿足 left < root &
資料結構實現 6.1:二叉堆_基於動態陣列實現(C++版)
資料結構實現 6.1:二叉堆_基於動態陣列實現(C++版) 1. 概念及基本框架 1.1 滿二叉樹 1.2 完全二叉樹 2. 基本操作程式實現 2.1 增加操作 2.2 刪除操作 2.3 查詢操作
資料結構實驗之棧與佇列四:括號匹配(SDUT 2134)
#include <bits/stdc++.h> using namespace std; typedef long long ll; char s[100]; char a[100]; int main() { int i,j,k,f,top,len; while(
排序演算法(四):堆排序(Heap Sort)
堆排序是一種樹形選擇排序,是對直接選擇排序的有效改進。 基本思想: 堆的定義如下:具有n個元素的序列(k1,k2,...,kn),當且僅當滿足 時稱之為堆。由堆的定義可以看出,堆頂元素(即第一個元素)必為最小項(小頂堆)。 若以一維陣列儲存一個堆,則堆對應一棵完全二叉樹,且所有
實驗四:順序佇列(迴圈佇列)和鏈佇列
#ifndef CirQueue_H #define CirQueue_H const int QueueSize=100; //定義儲存佇列元素的陣列的最大長度 template //定義模板類CirQueue class CirQueue { publ
替罪羊樹(Scapegoat Tree)
package com.yc.tree; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.List; /** * @au
git操作之四:git branch(本地倉庫)
前面,介紹了git init/add/commit/restore/reset等git命令,今天介紹下git branch,這個命令是和分支相關的。首先要理解什麼是分支,簡單來說在協作開發中,每個人開發的功能都是不一樣的,每個人在開發的時候總是在自己的分支上進行開發,待測試正常後會把程式碼合併到一個穩定的分支
面試題:平衡二叉樹
depth 二叉樹 面試 true 思路 nod balance urn oot 題目描述:輸入一棵二叉樹,判斷該二叉樹是否是平衡二叉樹。 思路:利用上一題求二叉樹的深度 public class Solution { public boolean IsBalan
劍指offer第55.5:平衡二叉樹
題目描述 輸入一棵二叉樹,判斷該二叉樹是否是平衡二叉樹。 class Solution: def IsBalanced_Solution(self, pRoot): # write code here if not pRoot:
劍指offer系列(十四)二叉樹的深度,平衡二叉樹,陣列中只出現一次的數字
二叉樹的深度 題目描述 輸入一棵二叉樹,求該樹的深度。從根結點到葉結點依次經過的結點(含根、葉結點)形成樹的一條路徑,最長路徑的長度為樹的深度。 解題思路: 利用遞迴實現。如果一棵樹只有一個結點,那麼它的深度為1。遞迴的時候無需判斷左右子樹是否存在,因為如果該節點 為葉節點,它的左右
演算法題(三十二):判斷二叉樹是否是平衡二叉樹
7. 判斷是否是BST 題目描述 輸入一棵二叉樹,判斷該二叉樹是否是平衡二叉樹。 分析 可以用遞迴的方法,從下向上遍歷各個結點(後序遍歷),如果結點是滿足BST的條件則返回該結點的高度,如果不滿足則直接停止遍歷並返回false。 程式碼 public cl
劍指offer:輸入一棵二叉樹,判斷該二叉樹是否是平衡二叉樹。
輸入一棵二叉樹,判斷該二叉樹是否是平衡二叉樹。 //後續遍歷二叉樹,遍歷過程中求子樹高度,判斷是否平衡 class Solution { public: bool IsBalanced(TreeNode *root, int & dep){
劍指offer-39:平衡二叉樹
題目描述 輸入一棵二叉樹,判斷該二叉樹是否是平衡二叉樹。 思路 首先,什麼是平衡二叉樹?如果二叉樹中任意結點的左右子樹深度相差不超過1,那麼它就是平衡二叉樹。 最直接的做法,遍歷每個結點,藉助一個獲取樹深度的遞迴函式,根據該結點的左右子樹高度差判斷是否平衡,然後遞迴地對左右子樹進
資料結構實驗之查詢二:平衡二叉樹 (SDUT 3374)
#include <stdio.h> #include <string.h> #include <stdlib.h> struct node { int data; int h; struct node *lc,*rc; //平衡二
面試題55(二):平衡二叉樹
一、題目 輸入一棵二叉樹的根結點,判斷該樹是不是平衡二叉樹。如果某二叉樹中任意結點的左右子樹的深度相差不超過1,那麼它就是一棵平衡二叉樹。 二、關鍵 三、解釋 四、程式碼 #include <cstdio> #include "..\Utilities\
#資料結構與演算法學習筆記#劍指Offer35:是否平衡二叉樹/AVL樹 + 測試用例(Java、C/C++)
2018.11.3 前幾天有用遞迴實現了二叉樹的深度#資料結構與演算法學習筆記#劍指Offer36:二叉樹的深度(Java),因此可以對每個結點先序遍歷進行一次平衡驗證,只要確定每個結點都是平衡的
搜尋二叉樹,平衡二叉樹,堆三者插入刪除操作分析總結
引言:搜尋二叉樹,平衡二叉樹,堆三者插入刪除操作在選擇題中經常出現,很容易混淆 所以在這裡就簡單總結一下: 一.搜尋二叉樹 定義:二叉查詢樹(Binary Search Tree),(又:二叉搜尋樹,二叉排序樹)它或者是一棵空樹,或者是具有下列性質的二叉樹: 若它的左子樹不空,則左子
AVL平衡二叉樹總結
我個人是通過b站學習的懂得 b站視訊連線: https://www.bilibili.com/video/av37955102?from=search&seid=14638889623357631324 https://www.bilibili.com/video/av379
簡直off: 平衡二叉樹
文章目錄 前言 題目 思路 暴力揭發 優化,從下往上的 前言 最近有道雲筆記老是沒響應,會員也這樣,所以把演算法的筆記公開到這個csdn,也算是公開的鞭策。 題目常練習起點位置: https://www.nowcod