【堆合并】左式堆

  1 #include <iostream>
  2 #include <cstdlib>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <string>
  6 #include <vector>
  7 #include <iterator>
  8 #include <stack>
  9 #include <algorithm>
 10 
 11 using namespace std;
 12 
 13 const int N = 100010;
 14 
 15 typedef struct LeftHeap *Lefh;
 16 
 17 Lefh Merge_node(Lefh, Lefh);    // 驱动Merge
 18 static Lefh Merge(Lefh, Lefh);  // 实际Merge
 19 Lefh inst(int, Lefh);   // 插入操作 视为 单节点堆与左式堆Merge
 20 Lefh DelteMin(Lefh);    // 删除最小元 视为 删掉根而得到两个堆,再把两者Merge
 21 void print(Lefh)        // bfs打印堆
 22 
 23 struct LeftHeap
 24 {
 25     int val;
 26     Lefh l;
 27     Lefh r;
 28     int npl;
 29 };
 30 
 31 Lefh q[N];
 32 
 33 Lefh Merge_node(Lefh h1, Lefh h2)
 34 {
 35     if (h1 == NULL) return h2;
 36     if (h2 == NULL) return h1;
 37     if (h1 -> val < h2 -> val)
 38         return Merge(h1, h2);
 39     else
 40         return Merge(h2, h1);
 41 }
 42 
 43 static Lefh Merge(Lefh h1, Lefh h2)
 44 {
 45     if (h1 -> l == NULL) h1 -> l = h2;  // 由此可以看出 Merge为O(logN)---合并堆的过程中,递归的次数取决于最右路径的长度,根据左式堆的结构性其最右路径最长为logN
 46     else
 47     {
 48         h1 -> r = Merge_node(h1 -> r, h2);
 49         if (h1 -> l -> npl < h1 -> r -> npl)    // 交换左右儿子
 50         {
 51             Lefh tmp = h1 -> l;
 52             h1 -> l = h1 -> r;
 53             h1 -> r = tmp;
 54         }
 55 
 56         h1 -> npl = h1 -> r -> npl + 1; // 左式堆:根节点及其左右儿子中,必定是 右儿子的npl最小,则根的npl 多1
 57     }
 58 
 59     return h1;
 60 }
 61 
 62 Lefh inst(int x, Lefh h)
 63 {
 64     Lefh t = (struct LeftHeap*) malloc(sizeof (LeftHeap));
 65 
 66     t -> val = x;
 67     t -> npl = 0;
 68     t -> l = t -> r = NULL;
 69     h = Merge_node(t, h);       // 单节点当成一棵子树插入
 70 
 71     return h;
 72 }
 73 
 74 Lefh DelteMin(Lefh h)
 75 {
 76     Lefh t = h;
 77     if (h -> l && !(h -> r)) h = h -> l;    // 只有左儿子
 78     else h = Merge_node(h -> l, h -> r);
 79     free(t);
 80     return h;
 81 }
 82 
 83 void print(Lefh h)
 84 {
 85     // bfs遍历树
 86 
 87     // 标记法:方便判断节点的顺序(徒手画图)     表示当前节点不存在左儿子或右儿子 就将 左儿子或右儿子标记为-1
 88     Lefh ept = (struct LeftHeap*) malloc(sizeof (LeftHeap));
 89     ept -> val = -1;
 90     ept -> l = ept -> r = NULL;
 91     ept -> npl = -1;
 92 
 93     int hh = 1, tt = 0;
 94     q[++ tt] = h;
 95 
 96     while (hh <= tt)
 97     {
 98         Lefh t = q[hh ++];
 99         printf("(%d,%d) ", t -> val, t -> npl);
100 
101         if (t -> val == -1) continue;
102         if (t -> l) q[++ tt] = t -> l; else q[++ tt] = ept;
103         if (t -> r) q[++ tt] = t -> r; else q[++ tt] = ept;
104     }puts("");
105 }
106 
107 int main()
108 {
109     int n, m, x;
110     cin >> n >> m;
111     Lefh h1 = NULL, h2 = NULL;
112     for (int i = 0; i < n; i ++)
113     {
114         scanf("%d", &x);
115         h1 = inst(x, h1);
116     }
117     for (int i = 0; i < m; i ++)
118     {
119         scanf("%d", &x);
120         h2 = inst(x, h2);
121     }
122     print(h1);
123     print(h2);
124 
125     Lefh H = Merge_node(h1, h2);
126     print(H);
127 
128     H = DelteMin(H);
129     print(H);
130 
131 
132     return 0;
133 }

 

posted @ 2020-11-24 20:44  ctxcc  阅读(177)  评论(0)    收藏  举报