資料結構——樹與二叉樹的性質,二叉樹的建立,遍歷,插入,列印,查詢左右兄弟等
阿新 • • 發佈:2019-02-13
#include<iostream> #include<string> #include<stack> using namespace std; #define MAX(x,y) (x) >= (y)?(x):(y) /* 結點的層次:從根到該結點的層數(根節點算第一層) 終端結點:度為0的結點,即葉子 分支結點:除樹根結點以外的結點,也稱內部結點 樹的度:所有結點中的最大值 MAX{各結點的度} 樹的深度:所有結點中的最大層數 Max{各結點的層次} 樹的表示方法:1.圖形表示法 2.廣義表表示方法 3.左孩子-右兄弟表示法 陣列的儲存方式:1.順序儲存:從上到下,從左到右的儲存方式,缺點:複雜困難,復原困難 2.鏈式儲存 將樹轉換為簡單的樹表示,進行操作 二叉樹的性質: 1.有序樹,左右子樹的順序不能互換 2.每個節點只能有兩個子樹 3.二叉樹每層上至多有2^(i-1)個結點, 4.深度為K的二叉樹,至多有2^k-1個結點, 5.二叉樹,2度的結點樹有n2個。則葉子樹n0必定為n2+1 滿二叉樹:深度為K且有2^(k-1)個結點的二叉樹 完全二叉樹:深度為k有n個結點的二叉樹,當且僅當每一個結點都與深度為k的滿二叉樹中編號從1到n的結點一一對應,只有最後一層葉子不滿,且都集中在左邊。 線索二叉樹的性質: 1.若結點有左子樹,則lchild指向左孩子;否則,lchild指向其直接前驅(即線索) 2.結點有右子樹,rchild指向右孩子,否則,rchild指向其直接後繼(即線索) 通過標誌位判定:Ltag Rtag 為0時,表示正常情況,為1時表示線索情況 */ struct tree { int nodedata=0; tree *LC=nullptr, *RC=nullptr; }; tree Btree, *pBtree; /* 1 2 3 4 5 6 層序,中序,前序,後序遍歷二叉樹 */ //遞迴方式列印二叉樹 void show(tree *proot,int n) { if (proot== nullptr ) { return; } else { show(proot->RC,n+2);//遞迴執行到右子樹的最後一個結點,沒有左右子樹為止 for (int i = 0;i < n;i++) { cout << ' '; } cout << proot->nodedata << endl;//列印結點資料 show(proot->LC, n + 2);//遍歷左子樹 } } //插入二叉樹 tree *insertnode(tree *proot, int num) { if (proot == nullptr) { tree *pnew = new tree; pnew->nodedata = num; proot = pnew; } else if(num<=proot->nodedata) { proot->LC = insertnode(proot->LC, num); } else { proot->RC = insertnode(proot->RC, num); } return proot; } //遞迴方式遍歷二叉樹 //中序遍歷二叉樹 void LDR(tree *proot) { if (proot == nullptr) { return; } LDR(proot->LC); cout << " " << proot->nodedata << endl; LDR(proot->RC); } //後序遍歷 void LRD(tree *proot) { if (proot == nullptr) { return; } LRD(proot->LC); LRD(proot->RC); cout << " " << proot->nodedata << endl; } //前序遍歷 void DLR(tree *proot) { if (proot == nullptr) { return; } cout << " " << proot->nodedata << endl; DLR(proot->LC); DLR(proot->RC); } //二叉樹的層序遍歷 void cengbianli(tree *proot) { if (proot == nullptr) { return; } tree * myq[100]; int tou = 0; int wei = 0; tree *pcurr = nullptr; myq[wei++] = proot;//存入佇列第一個結點,入隊 while (tou != wei) { pcurr = myq[tou];//取出第一個元素, tou++;//出隊,指向第二個元素的位置 cout << pcurr->nodedata << endl; if (pcurr->LC)//第二個元素入隊,然後指向下一個位置 { myq[wei++] = pcurr->LC; } if (pcurr->RC) { myq[wei++] = pcurr->RC; } } } //非遞迴方式遍歷二叉樹 void shuzhuLDR(tree *proot) { tree * pcurr = proot; tree * mytree[20]; int top=0; while (top != 0 || pcurr != nullptr) { while (pcurr != nullptr) { mytree[top++] = pcurr; pcurr = pcurr->LC; } if (top > 0) { top--; pcurr = mytree[top]; cout << " " << pcurr->nodedata << endl; pcurr = pcurr->RC; } } } //棧中序遍歷 void stackLDR(tree *proot) { tree * pcurr = proot; stack<tree *> mytree; while (!mytree.empty()|| pcurr != nullptr) { while (pcurr != nullptr) { mytree.push(pcurr); pcurr = pcurr->LC; } if(!mytree.empty()) { pcurr = mytree.top(); cout<< " " << mytree.top()->nodedata<< endl; mytree.pop(); pcurr = pcurr->RC; } } } //列印二叉樹的葉子結點個數 int getyezi(tree *proot) { int left = 0, right = 0; if (proot == nullptr) { return 0; } if(proot->LC==nullptr&&proot->RC==nullptr) { return 1; } left = getyezi(proot->LC); right = getyezi(proot->RC); return left + right; } //列印二叉樹的深度 int getheight(tree *proot) { int heightleft = 0,heightright=0; if (proot == nullptr) { return 0; } heightleft =getheight(proot->LC); heightright=getheight(proot->RC); return (heightleft >=heightright? heightleft : heightright)+1; } //獲得指定元素的父結點 int getroot(tree *proot, int num) { if (proot == nullptr) { return 0; } if (proot->LC != nullptr&&proot->LC->nodedata == num) { return proot->nodedata; } if (proot->RC != nullptr&&proot->RC->nodedata == num) { return proot->nodedata; } getroot(proot->LC,num); getroot(proot->RC,num); } //獲得左兄弟的值 int getleft(tree *proot, int num) { if (proot == nullptr) { return 0; } if (proot->RC && proot->RC->nodedata == num) { if (proot->LC) { return proot->LC->nodedata; } } return getleft(proot->LC, num)>=getleft(proot->RC, num)? getleft(proot->LC, num):getleft(proot->RC, num); } //獲得右兄弟的值 int getright(tree *proot, int num) { if (proot == nullptr) { return 0; } if (proot->LC &&proot->LC->nodedata == num) { if (proot->RC) { return proot->RC->nodedata; } } return getright(proot->LC,num) >= getleft(proot->RC, num) ? getright(proot->LC, num):getleft(proot->RC,num);//返回查詢結果 } //找到二叉樹中最大的元素 int findmax(tree *proot) { int max = -9999; tree * pcurr = proot; stack<tree *> mytree; while (!mytree.empty() || pcurr != nullptr) { while (pcurr != nullptr)//1 2 4 入棧 { mytree.push(pcurr); pcurr = pcurr->LC; } if (!mytree.empty()) { pcurr = mytree.top(); //cout << " " << mytree.top()->nodedata << endl; if (max < pcurr->nodedata) { max = pcurr->nodedata; } mytree.pop(); pcurr = pcurr->RC; } } return max; } void main1() { tree *proot;//根結點 tree s1, s2, s3, s4, s5, s6; s1.nodedata = 1; s1.LC = &s2; s1.RC = &s3; s2.nodedata = 2; s2.LC = &s4; s2.RC = &s5; s3.nodedata = 3; s3.LC = &s6; s3.RC = nullptr; s4.nodedata = 4; s5.nodedata = 5; s6.nodedata = 6; proot = &s1; insertnode(proot,7); show(proot,2); cout << "中序遍歷" << endl; LDR(proot); cout << "前序遍歷" << endl; DLR(proot); cout << "後序遍歷" << endl; LRD(proot); cout << "中序遍歷" << endl; cout << endl; shuzhuLDR(proot); cout << "中序遍歷" << endl; cout << endl; stackLDR(proot); cout << "葉子結點個數" << endl; cout << getyezi(proot) << endl; cout << "樹的深度" << endl; cout << getheight(proot) << endl; cout << "層序遍歷" << endl; cengbianli(proot); cout << "獲得指定元素的父結點"<<endl; cout << getroot(proot, 6) << endl; cout << "獲得左兄弟的值" << endl; cout << getleft(proot,5) << endl; cout << "獲得右兄弟的值" << endl; cout << getright(proot,4) << endl; cout << "findmax" << endl; cout<<findmax(proot) << endl; cin.get(); } void main2() { tree *proot; tree sarry[100]; proot = sarry; for (int i=1;i <= 100;i++) { sarry[i-1].nodedata = i; } for (int i = 0;i <= 50;i++) { if (i <= (99 - 1) / 2) { sarry[i].LC = &sarry[2 * i + 1]; } if (i <= (99 - 2) / 2) { sarry[i].RC = &sarry[2 * i + 2]; } } show(proot, 2); cin.get(); } void main() { tree *proot=nullptr; for (int i = 5;i < 10;i++) { proot = insertnode(proot,i); } for (int i = 4;i >0;i--) { proot = insertnode(proot, i); } show(proot,2); cin.get(); }