日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

BST基础教学(详细注释)

發布時間:2023/12/31 综合教程 23 生活家
生活随笔 收集整理的這篇文章主要介紹了 BST基础教学(详细注释) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<queue>
  4 #include<cstring>
  5 #include<algorithm>
  6 #define re return
  7 #define rep(i,a,n) for(int i = a;i <= n;i++)
  8 #define per(i,n,a) for(int i = n;i >= a;i--)
  9 typedef long long LL;
 10 using namespace std;
 11 int read() {
 12     int out = 0,flag = 1;
 13     char c = getchar();
 14     while(c < '0' || c > '9') {
 15         if(c == '-') flag = -1;
 16         c = getchar();
 17     }
 18     while(c >= '0' && c <= '9') {
 19         out = out * 10 + c - '0';
 20         c = getchar();
 21     }
 22     re flag * out;
 23 }
 24 //head
 25 
 26 const int maxn = 1000019,INF = 1e9;
 27 int na;
 28 int ch[maxn][2];//[i][0]代表i左兒子,[i][1]代表i右兒子
 29 int val[maxn],dat[maxn];
 30 int size[maxn],cnt[maxn];
 31 int tot,root;
 32 int New(int v) { //新增節點,
 33     val[++tot] = v;//節點賦值
 34     dat[tot] = rand();//隨機優先級
 35     size[tot] = 1;//目前是新建葉子節點,所以子樹大小為1
 36     cnt[tot] = 1;//新建節點同理副本數為1
 37     return tot;
 38 }
 39 void pushup(int id) { //和線段樹的pushup更新一樣
 40     size[id] = size[ch[id][0]] + size[ch[id][1]] + cnt[id];
 41     //本節點子樹大小 = 左兒子子樹大小 + 右兒子子樹大小 + 本節點副本數
 42 }
 43 void build() {
 44     root = New(-INF),ch[root][1] = New(INF);//先加入正無窮和負無窮,便于之后操作(貌似不加也行)
 45     pushup(root);//因為INF > -INF,所以是右子樹,
 46 }
 47 void Rotate(int &cur,int d) {
 48     int temp = ch[cur][d ^ 1];
 49     ch[cur][d ^ 1] = ch[temp][d];
 50     ch[temp][d] = cur;
 51     cur = temp;
 52     pushup(ch[cur][d]);
 53     pushup(cur);
 54     re;
 55 }
 56 void insert(int &id,int v) { //id依然是引用,在新建節點時可以體現
 57     if(!id) {
 58         id = ++tot;
 59         val[tot] = v;
 60         dat[tot] = rand();
 61         size[tot] = 1;
 62         cnt[tot] = 1;
 63         return;
 64     }
 65     if(v == val[id]) cnt[id]++;//若節點已存在,則副本數++;
 66     else { //要滿足BST性質,小于插到左邊,大于插到右邊
 67         bool d = (v > val[id]);
 68         insert(ch[id][d],v);//遞歸實現
 69         if(dat[id] < dat[ch[id][d]]) Rotate(id,d ^ 1);//(參考一下圖)與左節點交換右旋,與右節點交換左旋
 70     }
 71     pushup(id);//現在更新一下本節點的信息
 72 }
 73 void Del(int &id,int v) {
 74     if(!id)return ;//到這了發現查不到這個節點,該點不存在,直接返回
 75     if(v == val[id]) { //檢索到了這個值
 76         if(cnt[id] > 1) {
 77             cnt[id]--,pushup(id);    //若副本不止一個,減去一個就好
 78             return ;
 79         }
 80         if(ch[id][0] || ch[id][1]) { //發現只有一個值,且有兒子節點,我們只能把值旋轉到底部刪除
 81             if(!ch[id][1] || dat[ch[id][0]] > dat[ch[id][1]]) { //當前點被移走之后,會有一個新的點補上來(左兒子或右兒子),按照優先級,優先級大的補上來
 82                 Rotate(id,1),Del(ch[id][1],v);//我們會發現,右旋是與左兒子交換,當前點變成右節點;左旋則是與右兒子交換,當前點變為左節點
 83             } else Rotate(id,0),Del(ch[id][0],v);
 84             pushup(id);
 85         } else id = 0;//發現本節點是葉子節點,直接刪除
 86         return ;//這個return對應的是檢索到值de所有情況
 87     }
 88     v < val[id] ? Del(ch[id][0],v) : Del(ch[id][1],v);//繼續BST性質
 89     pushup(id);
 90 }
 91 int get_rank(int id,int v) {
 92     if(!id)return 0;//若查詢值不存在,返回
 93     if(v == val[id])return size[ch[id][0]] + 1;//查詢到該值,由BST性質可知:該點左邊值都比該點的值(查詢值)小,故rank為左兒子大小 + 1
 94     else if(v < val[id])return get_rank(ch[id][0],v);
 95     //發現需查詢的點在該點左邊,往左邊遞歸查詢
 96     else return size[ch[id][0]] + cnt[id] + get_rank(ch[id][1],v);
 97     //若查詢值大于該點值。說明詢問點在當前點的右側,且此點的值都小于查詢值,所以要加上cnt[id]
 98 }
 99 int get_val(int id,int rank) {
100     if(!id) return INF;//一直向右找找不到,說明是正無窮
101     if(rank <= size[ch[id][0]]) return get_val(ch[id][0],rank);
102     //左邊排名已經大于rank了,說明rank對應的值在左兒子那里
103     else if(rank <= size[ch[id][0]] + cnt[id]) return val[id];
104     //上一步排除了在左區間的情況,若是rank在左與中(目前節點)中,
105     //則直接返回目前節點(中區間)的值
106     else return get_val(ch[id][1],rank - size[ch[id][0]] - cnt[id]);
107     //剩下只能在右區間找了,rank減去左區間大小和中區間,繼續遞歸
108 }
109 int get_pre(int v) {
110     int id = root,pre;
111     while(id) {
112         if(val[id] < v) pre = val[id],id = ch[id][1];
113         else id = ch[id][0];
114     }
115     return pre;
116 }
117 int get_next(int v) {
118     int id = root,next;
119     while(id) {
120         if(val[id] > v) next = val[id],id = ch[id][0];
121         else id = ch[id][1];
122     }
123     return next;
124 }
125 int main() {
126     build();
127     //不要忘記初始化
128     //[運行build()會連同root一并初始化,所以很重要]
129     na = read();
130     for(int i = 1; i <= na; i++) {
131         int cmd = read(),x = read();
132         if(cmd == 1)insert(root,x);//函數都寫好了,注意:需要遞歸的函數都從根開始,不需要遞歸的函數直接查詢
133         if(cmd == 2)Del(root,x);
134         if(cmd == 3)printf("%d
",get_rank(root,x) - 1);//注意:因為初始化時插入了INF和-INF,所以查詢排名時要減1(-INF不是第一小,是“第零小”)
135         if(cmd == 4)printf("%d
",get_val(root,x + 1));//同理,用排名查詢值得時候要查x + 1名,因為第一名(其實不是)是-INF
136         if(cmd == 5)printf("%d
",get_pre(x));
137         if(cmd == 6)printf("%d
",get_next(x));
138     }
139     return 0;
140 }

個人認為除了把左右rotate和一起之外沒什么特別難懂的地方

至今沒人知道這份代碼的注釋為什么這么詳細

當年自己都這么認真現在有什么理由不努力呢

> 別忘了 總有人在等著你

總結

以上是生活随笔為你收集整理的BST基础教学(详细注释)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。