上篇博客介紹了一種非線性結構—普通樹 的含義以及一些特性,本文將介紹二叉樹、滿二叉樹以及徹底二叉樹的一些特性及實現。ios
首先,什麼是二叉樹?數組
二叉樹,是度爲二的樹,二叉樹的每個節點最多只有二個子節點,且兩個子節點有序。app
二叉樹的重要特性:測試
1.二叉樹的第i層上節點數最多2n-1。spa
2.高度爲k的二叉樹中,最多有2k-1個節點。code
3.在任意一棵二叉樹中,若是終端節點的度爲n,度爲2的節點數爲m,則n=m+1。blog
4.二叉樹的子樹有左右之分,順序不能顛倒。內存
5.若採用連續儲存的方式存放二叉樹,則節點下標之間的關係:ci
若某個節點的下標爲 i ,則這個節點的父節點的下標爲 i / 2。get
若某個節點下標爲 i ,且節點的度爲2,則這個節點的左子節點的下標爲 2 * i + 1 ,右子節點的下標爲 2 * i + 2 。
滿二叉樹:樹最後一層沒有任何子節點,其他每一層的全部節點都有2個子節點。
滿二叉樹的性質:
1.滿二叉樹的第i層的節點數爲2n-1個。
2.深度爲k的滿二叉樹必有2k-1個節點 ,葉子數爲2k-1。
3.滿二叉樹中不存在度爲1的節點,每個分支點中都兩棵深度相同的子樹,且葉子節點都在最底層。
4.具備n個節點的滿二叉樹的深度爲log2(n+1)。
徹底二叉樹:若是二叉樹的深度爲k,則除第k層外其他全部層節點的度都爲2,且葉子節點從左到右依次存在。也便是,將滿二叉樹的最後一層從左到右依次刪除若干節點就獲得徹底二叉樹。滿二叉樹是一棵特殊的徹底二叉樹,但徹底二叉樹不必定是滿二叉樹。
徹底二叉樹的性質:
1.滿二叉樹是一棵特殊的徹底二叉樹,但徹底二叉樹不必定是滿二叉樹。
2.在滿二叉樹中最下一層,連續刪除若干個節點獲得徹底二叉樹。
3.在徹底二叉樹中,若某個節點沒有左子樹,則必定沒有有子樹。
4.若採用連續儲存的方式存放二叉樹,則節點下標之間的關係(根節點下標爲0):
若某個節點的下標爲 i ,則這個節點的父節點的下標爲 i / 2。
若某個節點下標爲 i ,且節點的度爲2,則這個節點的左子節點的下標爲 2 * i + 1 ,右子節點的下標爲 2 * i + 2 。
除了根節點外,左子樹的下標爲基數,右子樹的下標爲偶數。
[ MyBinaryTree.h ]
1 /********************************************** 2 徹底二叉樹類模板 樹組實現 3 2018/3/22 4 /**********************************************/
5
6
7 #pragma once
8 using namespace std; 9 #include "stdafx.h"
10 #include <iostream>
11
12 template<class T>
13 class MyBinaryTree 14 { 15 private: 16 T *pRoot; //採用動態數組存儲
17 size_t len; 18 size_t maxSize; 19
20 void _sizeExpand(); 21 int _find(const T& val); //在樹中查找元素並返回他在容器中的下標 ,若沒找到返回-1;
22
23 public: 24 MyBinaryTree(); 25 ~MyBinaryTree(); 26 void clear(); //清空二叉樹
27 void appand(const T& val); //在徹底二叉樹尾部追加數據
28 T& find(const T& findVal); //在樹中查找元素並返回鈣元素的引用
29 bool isFind(const T& findVal); 30 void initTree(const T arr[], size_t n); //傳入一個數組 初始化樹
31 T& getParent(const T& val); 32 T& getLef/Child(const T& val); 33 T& getRightChild(const T& val); 34
35 void prePrint(int index = 0); 36 void posPrint(int index = 0); 37 void inPrint(int index = 0); 38
39
40 }; 41
42 template<class T>
43 void MyBinaryTree<T>::inPrint(int index /*= 0*/) 44 { 45 if (index < (int)len&&index >= 0) 46 { 47 inPrint(2 * index + 1); 48 cout << pRoot[index] << " "; 49 inPrint(2 * index + 2); 50 } 51 } 52
53 template<class T>
54 void MyBinaryTree<T>::posPrint(int index /* = 0*/) 55 { 56 if (index < (int)len&&index >= 0) 57 { 58 posPrint(2 * index + 1); 59 posPrint(2 * index + 2); 60 cout << pRoot[index] << " " ; 61 } 62 } 63
64 template<class T>
65 void MyBinaryTree<T>::prePrint(int index /* = 0*/) 66 { 67 if (index < (int)len&&index >= 0) 68 { 69 cout << pRoot[index]<<" "; 70 prePrint(2 * index + 1); 71 prePrint(2 * index + 2); 72 } 73 } 74
75 template<class T>
76 T& MyBinaryTree<T>::getRightChild(const T& val) 77 { 78 int temp = _find(val); 79 if (temp == -1 || 2 * temp + 2 >= len) //沒有找到元素,或者沒有右子樹
80 { 81 throw"the data has no rightchild"; 82 } 83 return pRoot[2 * temp + 2]; 84 } 85
86 template<class T>
87 T& MyBinaryTree<T>::getLeftChild(const T& val) 88 { 89 int temp = _find(val); 90 if (temp == -1 || 2 * temp + 1 >= len) //沒有找到元素,或者沒有左子樹
91 { 92 throw"the data has no leftchild"; 93 } 94 return pRoot[2 * temp + 1]; 95 } 96
97 template<class T>
98 T& MyBinaryTree<T>::getParent(const T& val) 99 { 100 int temp=_find(val); 101 if (temp == 0) //返回0,表示val爲根節點 ,沒有父親
102 cout << "該節點爲根節點,沒有父親" << endl; 103 return -1; 104 if (temp == -1) //沒有找到數據val
105 throw "the data is not in zhe tree"; 106 else
107 return pRoot[(temp - 1) >> 1 ]108 } 109
110 template<class T>
111 void MyBinaryTree<T>::initTree(const T arr[], size_t n) 112 { 113 clear(); //初始化以前先 判斷樹是否爲空 若不是,則先清空
114 len = n; 115 maxSize = n; 116 pRoot = new T[maxSize]; 117 memcpy_s(pRoot, len*sizeof(T), arr, len*sizeof(T)); 118
119 // for (size_t i = 0; i < n; i++) 120 // { //循環效率過低,直接內存拷貝 121 // //_sizeExpand(); 效率低 指直接一次性申請內存 //插入數據以前 先判斷容器是否已滿 122 // pRoot[i] = arr[i]; 123 // len++; 124 // }
125 } 126
127 template<class T>
128 int MyBinaryTree<T>::_find(const T& val) 129 { 130 for (int i = 0; i < len;++i) 131 { 132 if (public[i] == val) 133 return i; 134 } 135 return -1; 136 } 137
138
139 template<class T>
140 bool MyBinaryTree<T>::isFind(const T& findVal) 141 { 142 return _find(findVal)!=-1; 143 } 144
145 template<class T>
146 T& MyBinaryTree<T>::find(const T& findVal) 147 { 148 int tempIndex = _find(findVal); 149 if (tempIndex != -1) 150 return pRoot[tempIndex]; 151 else
152 throw "can not find the data"; 153 } 154
155 template<class T>
156 void MyBinaryTree<T>::_sizeExpand() 157 {//只擴充容量 容器沒存盡是不擴充
158 if (len>=maxSize) 159 { 160 maxSize = maxSize +(( maxSize / 2 > 1) ? maxSize / 2 : 1); 161 T *temp = new T[maxSize]; 162 if (pRoot) 163 { 164 memcpy_s(temp, len*sizeof(T), pRoot, len*sizeof(T)); 165 delete[]pRoot; 166 pRoot = temp; 167 } 168 } 169 } 170
171 template<class T>
172 void MyBinaryTree<T>::appand(const T& val) 173 { 174 _sizeExpand(); 175 pRoot[len++] = val; 176 } 177
178 template<class T>
179 void MyBinaryTree<T>::clear() 180 { 181 if (pRoot) //若樹爲非空 刪除內存空間
182 delete[]pRoot; 183 pRoot = NULL; 184 len = maxSize = 0; 185 } 186
187 template<class T>
188 MyBinaryTree<T>::~MyBinaryTree() 189 { 190 clear(); 191 } 192
193 template<class T>
194 MyBinaryTree<T>::MyBinaryTree() 195 { 196 pRoot = NULL; 197 len = maxSize = 0; 198 }
代碼測試:
1 // 徹底二叉樹.cpp : 定義控制檯應用程序的入口點。 2 // 3
4 #include "stdafx.h"
5 #include "MyBinaryTree.h"
6 #include <iostream>
7
8 using namespace std; 9
10 int _tmain(int argc, _TCHAR* argv[]) 11 { 12 MyBinaryTree<int> tree; 13 int arr[10]; 14 for (int i = 0; i < 10; ++i) 15 arr[i] = i; 16 cout << "徹底二叉樹初始化並遍歷打印" << endl; 17 tree.initTree(arr, 10); 18 cout << "前序遍歷: " ; 19 tree.prePrint(); cout << endl; 20 cout << "中序遍歷: "; 21 tree.inPrint(); cout << endl; 22 cout << "後序遍歷: " ; 23 tree.posPrint(); cout << endl; 24 cout << "----------------------------------" << endl; 25
26 cout << "在樹的葉節點增長數據:" << endl; 27 tree.appand(10); 28 tree.appand(11); 29 tree.prePrint(); cout << endl; 30 tree.appand(12); 31 tree.appand(13); 32 tree.prePrint(); cout << endl; 33 cout << "----------------------------------" << endl; 34
35 cout << "得到父節點、左右子節點:" << endl; 36 cout << "4的父節點:" << tree.getParent(4) << endl; 37 cout << "4的左子節點:" << tree.getLeftChild(4) << endl; 38 cout << "4的右子節點:" << tree.getRightChild(4) << endl; 39
40
41
42
43 cin.get(); 44 return 0; 45 }
運行結果: