struct BNode {
char data;
BNode *lChild, *rChild;
BNode(char a) {
data = a;
}
};
複製代碼
1.使用帶終止符的前序遍歷
形式:ABC##DE#G##F###html
///前序遍歷建立二叉樹(帶停止標記)
void CreateBinTree_UsePreFlag(){
cout << "please input preOrder number with refuse value: " << endl;
CreateBinTree_UsePreFlag(root);
}
void CreateBinTree_UsePreFlag(BNode* &subTree) { //傳入的指針必定要是引用,不然沒法修改傳入指針的指向位置
char item;
if (cin >> item)
{
if (item != refuseValue)
{
subTree = new BNode(item);
CreateBinTree_UsePreFlag(subTree->lChild);
CreateBinTree_UsePreFlag(subTree->rChild);
}
else {
subTree = NULL;
}
}
}
複製代碼
2.使用廣義表建立
廣義表形式:A(B(D,E(G,)),C(,F))#函數
///使用廣義表建立
void CreateBinTree_UseGenTable() {
cout << "please input Generalized table: " << endl;
CreateBinTree_UseGenTable(root);
}
///使用廣義表建立二叉樹函數,這裏以「字符」建立二叉樹,以'#'字符表明結束
void CreateBinTree_UseGenTable(BNode* &BT) {
stack<BNode*> s;
BT = NULL;
BNode *p, *t; //p用來記住當前建立的節點,t用來記住棧頂的元素
int k; //k是處理左、右子樹的標記
char ch;
while (1)
{
cin >> ch;
if (ch == refuseValue)
break;
switch (ch)
{
case '(': //對(作處理
s.push(p);
k = 1;
break;
case ')': //對)作處理
s.pop();
break;
case ',': //對,作處理
k = 2;
break;
default:
p = new BNode(ch); //構造一個結點,!注意要給新節點的左右孩子指針賦空值!
p->lChild = NULL;
p->rChild = NULL;
if (BT == NULL) //若是頭節點是空
{
BT = p;
}
else {
if (k == 1) //鏈入*t的左孩子
{
t = s.top();
t->lChild = p;
}
else //鏈入*t的右孩子
{
t = s.top();
t->rChild = p;
}
}
}
}
}
複製代碼
3.使用前序遍歷和中序遍歷建立post
///使用先序遍歷和中序遍歷建立
void CreateBinTree_Pre_mid() {
char pre[50];
char mid[50];
cout << "please input preOrder: " << endl;
cin >> pre;
cout << "please input midOrder: " << endl;
cin >> mid;
string s1(pre);
string s2(mid);
if (s1.length() != s2.length()) {
cout << "error input!" << endl;
return;
}
int n = s1.length();
CreateBinTree_Pre_mid(root,pre,mid,n);
}
void CreateBinTree_Pre_mid(BNode *&cur, const char *pre, const char *mid, int n) {
if (n <= 0)
{
cur = NULL;
return;
}
int k = 0;
while (pre[0] != mid[k]) {
k++;
}
cur = new BNode(mid[k]); //建立結點
CreateBinTree_Pre_mid(cur->lChild, pre + 1, mid,k);
CreateBinTree_Pre_mid(cur->rChild, pre + k + 1, mid + k + 1,n-k-1);
}
複製代碼
4.使用後續遍歷和中序遍歷建立ui
///使用後序遍歷和中序遍歷建立(與上方法相似)
void CreateBinTree_post_mid() {
char post[50];
char mid[50];
cout << "please input postOrder: " << endl;
cin >> post;
cout << "please input midOrder: " << endl;
cin >> mid;
string s1(post);
string s2(mid);
if (s1.length() != s2.length()) {
cout << "error input!" << endl;
return;
}
int n = s1.length();
CreateBinTree_post_mid(root, post, mid, n);
}
///後序遍歷和中序遍歷建立二叉樹
void CreateBinTree_post_mid(BNode* &cur, const char *post, const char *mid, int n) {
if (n <= 0)
{
cur = NULL;
return;
}
int k = 0;
while (post[n - 1] != mid[k]) {
k++;
}
cur = new BNode(mid[k]);
CreateBinTree_post_mid(cur->lChild, post, mid, k);
CreateBinTree_post_mid(cur->rChild, post + k, mid + k+1,n-k-1);
}
複製代碼
1.先序遍歷spa
///先序遍歷
void preOrder() {
cout << "preOrder num: ";
//遞歸遍歷
// preOrderPrint_UseRecursion(root);
//使用棧遍歷
// preOrderPrint_UseStack1();
preOrderPrint_UseStack2();
cout << endl;
}
//1 遞歸遍歷
void preOrderPrint_UseRecursion(BNode* subTree) {
if (subTree != NULL) {
cout << subTree->data << " ";
preOrderPrint_UseRecursion(subTree->lChild);
preOrderPrint_UseRecursion(subTree->rChild);
}
}
//2.1 利用棧實現前序遍歷的過程。每次訪問一個結點後,在向左子樹遍歷下去以前,利用這個棧記錄該結點的右子女(若是有的話)結點的地址,
//以便在左子樹退回時能夠直接從棧頂取得右子樹的根結點,繼續其右子樹的前序遍歷。
void preOrderPrint_UseStack1() {
stack<BNode*> s;
BNode* p=root;
s.push(NULL);
while (p != NULL) {
cout << p->data << " ";
if (p->rChild != NULL)
s.push(p->rChild);
if (p->lChild != NULL)
{
p = p->lChild; //把當前還未處理的右孩子指針存起來
}
else {
p = s.top();
s.pop();
}
}
cout << endl;
}
//2.2 爲了保證先左子樹後右子樹的順序,在進棧時是先進右子女結點地址,後進左子女結點地址,出棧時正好相反。
void preOrderPrint_UseStack2() {
BNode* p = root;
stack<BNode*> s;
s.push(p);
while (!s.empty()) {
p = s.top();
s.pop();
cout << p->data << " ";
if (p->rChild != NULL)
s.push(p->rChild);
if(p->lChild!=NULL)
s.push(p->lChild);
}
cout << endl;
}
複製代碼
2.中序遍歷指針
void midOrder() {
cout << "midOrder num: ";
///遞歸遍歷
midOrderPrint_UseRecursion(root);
///使用棧遍歷
// midOrderPrint_UseStack();
cout << endl;
}
//1.遞歸進行遍歷
void midOrderPrint_UseRecursion(BNode* subTree) {
if (subTree != NULL) {
midOrderPrint_UseRecursion(subTree->lChild);
cout << subTree->data << " ";
midOrderPrint_UseRecursion(subTree->rChild);
}
}
//2.使用棧進行遍歷
void midOrderPrint_UseStack() {
BNode* p = root;
stack<BNode*> s;
do{
while (p != NULL) {
s.push(p);
p = p->lChild;
}
if (!s.empty()) {
p = s.top();
s.pop();
cout << p->data << " ";
p = p->rChild;
}
} while (p != NULL || !s.empty());
}
複製代碼
3.後續遍歷code
///後序遍歷
void postOrder() {
cout << "postOrder num: ";
//遞歸遍歷
// postOrderPrint_UseRecursion(root);
//使用棧遍歷
postOrderPrint_UseStack();
cout << endl;
}
//1.遞歸進行遍歷
void postOrderPrint_UseRecursion(BNode* subTree) {
if (subTree != NULL) {
postOrderPrint_UseRecursion(subTree->lChild);
postOrderPrint_UseRecursion(subTree->rChild);
cout << subTree->data << " ";
}
}
//2.使用棧進行遍歷
void postOrderPrint_UseStack() {
if (root == NULL)
return;
BNode *p = root;
stack<BNode *> s;
s.push(p);
BNode *lastPop = NULL;
while (!s.empty())
{
while (s.top()->lChild != NULL)
s.push(s.top()->lChild);
while (!s.empty())
{
//右葉子結點 || 沒有右結點
if (lastPop == s.top()->rChild || s.top()->rChild == NULL)
{
cout << s.top()->data << " ";
lastPop = s.top();
s.pop();
}
else if (s.top()->rChild != NULL)
{
s.push(s.top()->rChild);
break;
}
}
}
}
複製代碼
4.先序遍歷(廣義表形式)htm
///先序遍歷,廣義表形式
void preOrder_GenTable() {
cout << "preOrder num with generalize table: ";
GenTablePrint(root);
cout << endl;
}
///二叉樹以廣義表形式輸出
void GenTablePrint(BNode *BT) {
if (BT != NULL) //樹爲空時結束遞歸
{
cout << BT->data;
if (BT->lChild != NULL || BT->rChild != NULL)
{
cout << '(';
if (BT->lChild != NULL)
{
GenTablePrint(BT->lChild);
}
cout << ',';
if (BT->rChild != NULL)
{
GenTablePrint(BT->rChild);
}
cout << ')';
}
}
}
複製代碼
5.層次遍歷blog
///層次遍歷(使用隊列實現)
void levelOrderPrint() {
BNode* p = root;
queue<BNode*> Queue;
Queue.push(p);
while (1) {
if(p->lChild!=NULL)
Queue.push(p->lChild);
if (p->rChild != NULL)
Queue.push(p->rChild);
cout << p->data << " ";
Queue.pop();
if (Queue.empty())
break;
else
p = Queue.front();
}
}
複製代碼
1.獲取根節點遞歸
BNode* getRoot() {
return root;
}
複製代碼
2.獲取二叉樹節點數量
int size() { //二叉樹大小
return size(root);
}
///節點p開頭的子樹節點數目
int size(BNode* p) {
if (p == NULL)
return 0;
return 1 + size(p->lChild) + size(p->rChild);
}
複製代碼
3.獲取二叉樹高度
int height() {
//return height_UseStack(root);
return height_UseRecursion(root);
}
///節點p開頭的子樹節點高度
int height_UseRecursion(BNode *p) {
if (p == NULL)
return 0;
int i = height_UseRecursion(p->lChild);
int j = height_UseRecursion(p->rChild);
return i > j ? i + 1 : j + 1;
}
int height_UseStack(BNode *T) {
if (!T)
return 0;
int front = -1, rear = -1;
int last = 0, level = 0;
BNode* tree[100];
tree[++rear] = T;
BNode* p;
while (front < rear) {
p = tree[++front];
if (p->lChild != 0)
tree[++rear] = p->lChild;
if (p->rChild != NULL)
tree[++rear] = p->rChild;
if (front == last)
{
level++;
last = rear;
}
}
return level;
}
複製代碼
4.尋找某個節點的父節點
BNode* parent(BNode* subTree, BNode* current) {
if (subTree == NULL)
return NULL;
if (subTree->lChild == current || subTree->rChild == current)
return subTree;
BNode* p;
if ((p = parent(subTree->lChild, current)) != NULL)
return p;
else
return parent(subTree->rChild, current);
}
複製代碼
5.銷燬二叉樹並回收空間
void destroy(BNode *p) {
if (p == NULL)
return;
else {
destroy(p->lChild);
destroy(p->rChild);
delete p;
p = NULL;
}
}
複製代碼
6.判斷兩個二叉樹是否一致(靜態函數)
static bool equal(BNode* a, BNode *b) {
if (a == NULL&&b == NULL)
return true;
if (a != NULL&&b != NULL && (a->data == b->data) && equal(a->rChild, b->rChild) && equal(a->lChild, b->lChild))
return true;
else
return false;
}
複製代碼
7.判斷是不是徹底二叉樹
///判斷是不是徹底二叉樹_方法1 使用層次遍歷,h-1層的最後一個節點序號爲pow(2, level - 1) - 1
bool isFullBinaryTree_1() {
BNode *T = root;
if (!T)
return true;
int front = -1, rear = -1;
int last = 0, level = 0;
BNode* a[100];
stack<int> frontHistory;
a[++rear] = T;
BNode* p;
while (front < rear) {
p = a[++front];
if (p->lChild != NULL)
a[++rear] = p->lChild;
if (p->rChild != NULL)
a[++rear] = p->rChild;
if (front == last) {
last = rear;
level++;
frontHistory.push(front);
}
}
frontHistory.pop();
//只須要驗證h-1層最後一個節點序號是不是2^(h-1)-1便可!
return (frontHistory.top()+1) == (pow(2, level - 1) - 1);
}
///判斷是不是徹底二叉樹_方法2 利用性質:層次遍歷時出現一個葉子節點則後面的均爲葉子節點(空節點)
bool isFullBinaryTree_2() {
BNode* p = root;
queue<BNode*> que;
que.push(p);
while (!que.empty()) {
p = que.front();
que.pop();
if (p) {
que.push(p->lChild);
que.push(p->rChild);
}
else {
while (!que.empty())
{
p = que.front();
que.pop();
if (p)
return false;
}
}
}
return true;
}
複製代碼
8.交換節點p爲根節點的子樹的全部的左右節點
///交換節點p爲根節點的子樹的全部的左右節點(層次遍歷)
void swapLeftAndRight(BNode* p) {
// BNode* p = root;
if (!p)
return;
queue<BNode*> que;
que.push(p);
while (!que.empty()) {
p = que.front();
que.pop();
if (p->lChild != NULL)
que.push(p->lChild);
if (p->rChild != NULL)
que.push(p->rChild);
swap(p);
}
}
複製代碼
9.輸出中序遍歷的第i個值,其餘遍歷方法相似
void valueOfMidOrderNo(int i) {
int No = 0;
recursiveMidOrderTemp(root, i,No);
}
///輸出中序遍歷的第n的節點的值
void recursiveMidOrderTemp(BNode * subTree, int i, int &No) {//No須要全部遞歸部分共同維護
if (subTree != NULL) {
recursiveMidOrderTemp(subTree->lChild, i, No);
// cout << subTree->data << " ";
No++;
if (No == i) {
cout << subTree->data << endl;
return;
}
if (No > i)
return;
recursiveMidOrderTemp(subTree->rChild, i, No);
}
}
複製代碼
10.遞歸遍歷尋找頂點到節點值爲X的路徑(此爲逆序輸出)
void printWayToX(char x) {
//printWayToX_UseRecursion(root, x);
printWayToX_UseStack(root, x);
cout << endl;
}
//1.使用遞歸實現
bool printWayToX_UseRecursion(BNode* p, char x) {
if (!p)
return false;
if (printWayToX_UseRecursion(p->lChild, x) || printWayToX_UseRecursion(p->rChild, x))
{
cout << p->data;
return true;
}
else if (p->data == x)
{
cout << p->data;
return true;
}
else {
return false;
}
}
//2.非遞歸遍歷尋找。使用後序遍歷,當查找到x時,棧中元素即爲x的祖節點
void printWayToX_UseStack(BNode* p, char x) {
stack<BNode*> s;
BNode* lastPos = NULL;
s.push(p);
while (!s.empty()) {
while (s.top()->lChild != NULL)
{
s.push(s.top()->lChild);
//節點值爲x的節點入棧後,直接將棧中元素所有輸出而後退出該函數
if (s.top()->data == x) {
while (!s.empty()) {
cout << s.top()->data << " ";
s.pop();
}
return;
}
}
while (!s.empty())
{
if (lastPos == s.top()->rChild || s.top()->rChild == NULL)
{
lastPos = s.top();
s.pop();
}
else if (s.top() != NULL)
{
s.push(s.top()->rChild);
//查找到x時,直接將棧中元素所有輸出而後退出該函數
if (s.top()->data == x) {
while (!s.empty()) {
cout << s.top()->data << " ";
s.pop();
}
return;
}
break;
}
}
}
}
複製代碼
11.找到值爲 x 和 y的最近公共祖先節點。先分別利用後序查找x y的祖先節點存儲在棧中,再在兩個棧中查找最近相同節點!
char ClosestAncestorNode(char x, char y) {
if (root == NULL)
return '#';
stack<BNode*> s1,s2;
AncestorsNodeStack(x,s1);
AncestorsNodeStack(y,s2);
if (s1.empty() || s2.empty())
return '#';
int n = 0;
if (s1.size() >= s2.size())
{
n = s1.size() - s2.size();
for (int i = 0; i < n; i++)
s1.pop();
}
else {
n = s2.size() - s1.size();
for (int i = 0; i < n; i++)
s2.pop();
}
while (!s1.empty()) {
if (s1.top()->data == s2.top()->data)
return s1.top()->data;
s1.pop();
s2.pop();
}
return '#';
}
///返回存儲節點值爲x的祖先節點的棧
void AncestorsNodeStack(char x, stack<BNode*> &s) {
if (root == NULL)
return;
BNode* lastPos = NULL;
s.push(root);
while (!s.empty()) {
while (s.top()->lChild != NULL)
{
s.push(s.top()->lChild);
//節點值爲x的節點入棧後,停止該函數
if (s.top()->data == x)
return;
}
while (!s.empty())
{
if (lastPos == s.top()->rChild || s.top()->rChild == NULL)
{
lastPos = s.top();
s.pop();
}
else if (s.top() != NULL)
{
s.push(s.top()->rChild);
//查找到x時,停止該函數
if (s.top()->data == x)
return;
break;
}
}
}
}
複製代碼
12.二叉樹的最大寬度(節點最多的一層的節點數)
int WidthOfBTree() {
if (root == NULL)
return 0;
int maxWidth = 0;
int front, rear;
front = rear = -1;
int last = 0;
BNode* p = root;
BNode* a[100];
a[++rear] = p;
while (front < rear) {
p=a[++front];
if (p->lChild != NULL)
a[++rear] = p->lChild;
if (p->rChild != NULL)
a[++rear] = p->rChild;
if (front == last)
{
last = rear;
if (rear - front > maxWidth)
maxWidth = rear - front;
}
}
return maxWidth;
}
複製代碼