树 概念
树状图是一种数据结构,它是由 n(n>=1)个有限结点组成一个具有层次关系的集合。把它叫做“树”是因 为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:
每个结点有零个或多个子结点;没有父结点的结点称为根结点;每一个非根结点有且只有一个父结点;除 了根结点外,每个子结点可以分为多个不相交的子树。
二叉树
同线性表,一个没有限制条件的线性表就是一个数组,但是加以限制条件就得到了非常有用的栈、队列、优先队列等。
引出二叉树
树也是一样,一个没有限制的树由于太灵活,控制起来比较复杂。如果对普通的树加上一些人为的限制,比如 结点只允许有两个子结点,这就是二叉树。
二叉树是一个每个结点最多只能有两个分支的树,左边的分支称之为左子树,右边的分支称之为右子树。
如下图所示 :
(1).在非空二叉树中,第 i-1 层的结点总数不超过 , i>=1;
(2).深度为 h-1 的二叉树最多有 2的h次方个结点(h>=1),最少有 h 个结点;
(3).对于任意一棵二叉树,如果其叶结点数为 N0,而度数为 2 的结点总数为 N2,则 N0=N2+1;(叶子结点的个数=度为2的结点个数+1)
常见二叉树分类 完全二叉树
(1)完全二叉树—— 若设二叉树的高度为 h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层有叶 子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树(堆 就是完全二叉树)
满二叉树
(2)满二叉树——除了叶结点外每一个结点都有左右子结点且叶子结点都处在最底层的二叉树。
平衡二叉树
(3)平衡二叉树:又被称为 AVL 树,它是一颗空树或左右两个子树的高度差的绝对值不超过 1,并且左右两个子树都是一棵平衡二叉树。(高度从0开始数)
二叉搜索树
(4)二叉搜索树——又称二叉查找树、二叉排序树(Binary Sort Tree)。它是一棵空树或是满足下列性质的二叉树:
1)若左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值;
2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
3)左、右子树也分别为二叉搜索树。
(查找的效率非常高(类似于二分查找,每次对比几乎能去掉一半数据(理想情况下)) )
红黑树
红黑树 — 是每个结点都带有颜色属性(颜色为红色或黑色)的平衡二叉查找树,满足下列性质:
1)结点是红色或黑色;
2)根结点是黑色;
3)所有叶子结点都是黑色;
4)每个红色结点必须有两个黑色的子结点。(从每个叶子到根的所有路径上不能有两个连续的红色结点。)
5)从任一结点到其每个叶子的所有简单路径都包含相同数目的黑色结点。
二叉树搜索树实现 如果在一组有序的数组中插入一个数字,插入后仍保证这组数是有序的。
如果采用顺序表的形式,会涉及到大量数据的移动。
不移动大量数据可以用链表实现,但是寻找合适的位置还得遍历每个结点的data。如何高效的进行此操纵呢。
那么我们可以用二叉树的形式,以数据集第一个元素为根节点,之后将比根节点小的元素放在左子树中,将比根节点大的元素放在右子树中,在左右子树中同样采取此规则。那么在查找 x 时,若 x 比根节点小可以排除右子树所有元素, 去左子树中查找(类似二分查找),这样查找的效率非常好,而且插入的时间复杂度为 O(h),h 为树的高度,较 O(n)来说效率提高不少。故二叉搜索树用作一些查找和插入使用频率比较高的场景。
二叉搜索树一般采用链式存储方式,每个结点包含两个指针域和一个数据域,存储结点信息。
(能不用递归的地方尽量不用递归,因为如果递归的层级太深的话,容易导致栈溢出。)
Mystack.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 #include <iostream> using namespace std ;#define MAX_SIZE 128 typedef int DataTypeTree;typedef struct _Tnode //Tree { struct _Tnode * lchild ; struct _Tnode * rchild ; DataTypeTree data; }BNode, BTree; typedef BNode DataType;typedef struct _Stack { DataType* top; DataType* base; }Stack; bool initStack (Stack& S) { S.base = new DataType[MAX_SIZE]; if (!S.base) { return false ; } S.top = S.base; return true ; } bool pushStack (Stack& S, DataType data) { if (!S.base) { return false ; } if (S.top - S.base == MAX_SIZE) { return false ; } *(S.top) = data; S.top++; return true ; } bool popStack (Stack& S,DataType& e) { if (S.top == S.base) { return false ; } e = *(--S.top); return true ; } DataType* getTop (Stack& S) { if (S.top != S.base) { return S.top - 1 ; } else { return NULL ; } } bool isEmpty (Stack& s) { if (s.top == s.base) { return true ; } return false ; } bool destoryStack (Stack& s) { if (s.base) { delete [] s.base; s.base = s.top = NULL ; return true ; } return false ; }
test.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 #include <iostream> #include <assert.h> #include "mystack.h" using namespace std ;#define isLess(a,b) (a<b) #define isEqual(a,b) (a== b) bool insertBtree (BTree*& root, BNode* node) { BNode* tmp = NULL ; BNode* parent = NULL ; if (!node) { return false ; } else { node->lchild = NULL ; node->rchild = NULL ; } if (root) { tmp = root; } else { root = node; return true ; } while (tmp) { parent = tmp; if (isLess(node->data, tmp->data)) { tmp = tmp->lchild; } else { tmp = tmp->rchild; } } if (isLess(node->data, parent->data)) { parent->lchild = node; } else { parent->rchild = node; } return true ; } int findMax (BTree* root) { assert(root); if (root->rchild == NULL ) { return root->data; } return findMax(root->rchild); } BTree* deleteNode (BTree* root, int key, BNode*& DeleteNode) { if (!root) { return NULL ; } if (root->data > key) { root->lchild = deleteNode(root->lchild, key, DeleteNode); return root; } if (root->data < key) { root->rchild = deleteNode(root->rchild, key, DeleteNode); return root; } DeleteNode = root; if ((!root->lchild) && (!root->rchild)) { delete root; return NULL ; } if ((root->lchild) && (!root->rchild)) { return root->lchild; } if ((!root->lchild) && (root->rchild)) { return root->rchild; } int val = findMax(root->lchild); root->data = val; root->lchild = deleteNode(root->lchild, val, DeleteNode); return root; } void FrontPrint (BTree* root) { if (!root) { return ; } cout << root->data << " " ; FrontPrint(root->lchild); FrontPrint(root->rchild); } void MidPrint (BTree* root) { if (!root) { return ; } MidPrint(root->lchild); cout << root->data << " " ; MidPrint(root->rchild); } void BehindPrint (BTree* root) { if (!root) { return ; } BehindPrint(root->lchild); BehindPrint(root->rchild); cout << root->data << " " ; } BNode* Find1 (BTree* root, int key) { if (!root || isEqual(root->data, key)) { return root; } else if (isLess(key, root->data)) { return Find1(root->lchild, key); } else { return Find1(root->rchild, key); } } void Find2 (BTree* root, int key) { while (root) { if (isLess(root->data, key)) { root = root->rchild; } else if (isLess(key, root->data)) { root = root->lchild; } else { cout << "找到了" << endl ; break ; } } if (!root) { cout << "没找到" << endl ; } } BNode* Find3 (BTree* root, int key) { while (root && !isEqual(root->data, key)) { if (isLess(root->data, key)) { root = root->rchild; } else { root = root->lchild; } } return root; } void PrintFrontWithStack (BTree* root) { BNode cur; if (!root) { return ; } Stack Tstack; initStack(Tstack); pushStack(Tstack, *root); while (!isEmpty(Tstack)) { popStack(Tstack, cur); cout << cur.data << " " ; if (cur.rchild) { pushStack(Tstack,*(cur.rchild)); } if (cur.lchild) { pushStack(Tstack, *(cur.lchild)); } } cout << endl ; destoryStack(Tstack); } int main (void ) { int arr[8 ] = { 11 ,18 ,9 ,35 ,6 ,17 ,4 ,15 }; BTree* root = NULL ; BNode* node = NULL ; for (int i = 0 ; i < 8 ; i++) { node = new BNode; node->data = arr[i]; insertBtree(root, node); } BNode* DeleteNode = NULL ; FrontPrint(root); cout << endl ; PrintFrontWithStack(root); BehindPrint(root); return 0 ; }
实际应用 哈夫曼编码 (未完待续……)
红黑树 红黑树构建过程(略)