關於二叉樹的幾個基本操作
阿新 • • 發佈:2019-01-29
//Geeksun 2018.05.13 輸入樣例 AB#D##C## 詳情見擴充套件二叉樹 #include <iostream> using namespace std; enum flag{Child = 0,Thread = 1};//兩種列舉型別,表示該節點的指標是指向下一個節點,還是作為線索。 struct node { char data; struct node *leftChild, *rightChild; flag ltag, rtag; }; class Tree { public: Tree() { this->root = treeCreat(getRoot());//此處需要在類裡再定義一個建立樹的函式,因為建構函式不能被遞迴呼叫。 pre = NULL; threadTreeCreat(getRoot()); } Tree(const Tree& tree)//複製建構函式 { this->root = treeCopy(this->root,tree.root); } ~Tree() { destroyTree(getRoot()); } void destroyTree(struct node* node);//析構整個樹 bool isCompleteBinaryTree(struct node* node);//判斷是否為完全二叉樹 void threadInorder_travelsal(struct node* node);//根據線索二叉樹中序遍歷 void deleteNodeTree(char data, struct node* node, struct node* pre);刪除子樹 bool searchNode(char data, struct node* node, struct node*& cur, bool &isFind);//查詢某個節點 struct node** arrayReserve(struct node* node,int& count);//將樹按中序儲存在陣列中 struct node* getRoot() { return root; } private: struct node* root; struct node* pre; struct node* treeCreat(struct node* node); struct node* treeCopy(struct node* son_node,struct node* father_node); struct node* threadNext(struct node* p);//中序遍歷時查詢後繼節點的位置 void threadTreeCreat(struct node* node); }; bool Tree::isCompleteBinaryTree(struct node* node) { int head = 0, tail = 0; struct node* queue[20]; if (!node) { return false; } queue[tail++] = node; while (head != tail) { struct node* p; p = queue[head++ % 20]; if (p->leftChild != NULL&&p->rightChild != NULL)//若左孩子,右孩子不為空則直接入佇列 { queue[tail++ % 20] = p->leftChild; queue[tail++ % 20] = p->rightChild; } if (p->leftChild == NULL&&p->rightChild != NULL)//若有右孩子沒有左孩子則不是完全二叉樹 { return false; } if (p->leftChild != NULL && p->rightChild == NULL|| p->leftChild == NULL && p->rightChild == NULL)//若左孩子和右孩子存在或左孩子和右孩子都不存在,則在此節點後的全是葉子結點 { while (head != tail) { p = queue[head]; if (p->leftChild == NULL && p->rightChild == NULL) { head++; } else { return false; } } return true; } } return true; } struct node* Tree::treeCopy(struct node* son_node, struct node* father_node) { if (father_node) { son_node = new struct node; son_node->data = father_node->data; son_node->leftChild = treeCopy(son_node->leftChild, father_node->leftChild);//此處的struct node* son_node 可以用引用,因為要修改它的指向,也可以在修改後將它傳出來,覆蓋之前的指標。 son_node->rightChild = treeCopy(son_node->rightChild, father_node->rightChild); } else { son_node = NULL;//此處一定要加上新節點為空,不然它就是一個野指標了。 } return son_node; } bool Tree::searchNode(char data, struct node* node, struct node*& cur,bool &isFind)//此處isFind傳引用較為新穎,只要isFind被修改為True,那麼就可以知道,在節點中有該資料。 { if (!node) { return isFind; } if (node->data == data) { cur = node; isFind = true; return isFind; } searchNode(data, node->leftChild, cur, isFind); searchNode(data, node->rightChild, cur, isFind); return isFind; } void Tree::deleteNodeTree(char data,struct node* node,struct node* pre) { if (node != NULL) { if (node->data == data && node != getRoot())//如果刪除的不是根節點 { if (pre->leftChild == node) //防止刪除節點的父節點的指標懸空 pre->leftChild = NULL; else if (pre->rightChild == node) pre->rightChild = NULL; destroyTree(node); return; } else if (node->data == data) { destroyTree(node); return; } if(node->ltag == 0) deleteNodeTree(data,node->leftChild,node); if(node->rtag == 0) deleteNodeTree(data,node->rightChild,node); } } void Tree::threadInorder_travelsal(struct node* node) { struct node* p; p = node; if (!p) { return; } while (p->ltag == 0) { p = p->leftChild;//先找到樹最左下方的節點。 } cout << p->data; while (p->rightChild != NULL) { p = threadNext(p); cout << p->data; } } struct node** Tree::arrayReserve(struct node* node,int &count) { int head = 0, tail = 0; count = 0; struct node** array = new struct node*[20];//這裡需要在堆中建立陣列,因為如果在棧中建立陣列,當函式結束後array中的資料都會消失,而堆中資料需自己清空。 struct node* queue[20]; if (!node) { return NULL; } queue[tail++ % 20] = node; while (head != tail) { struct node* q = queue[head++]; array[count++] = q; if (q->leftChild != NULL) queue[tail++] = q->leftChild; if (q->rightChild != NULL) queue[tail++] = q->rightChild; } return array; } struct node* Tree::threadNext(struct node* p) { struct node* q; if (p->rtag == 1) q = p->rightChild; else { q = p->rightChild;//此處p的右孩子不可能為空,若為空則他的rtag一定為1 while (q->ltag == 0) { q = q->leftChild; } } return q; } void Tree::threadTreeCreat(struct node* node) { if (node == NULL) return; threadTreeCreat(node->leftChild); if (node->leftChild == NULL) { node->ltag = (flag)1;//這裡要使用強轉型別轉換,不然會報錯! node->leftChild = pre; } if (node->rightChild == NULL) node->rtag = (flag)1;//右孩子指標指向的是下一個中序結點的地址,但是暫時還不知道下一個是誰,因此只能在下一輪迴圈指向下一個結點。 if (pre != NULL&& pre->rtag == 1)//當pre為指向空的時候,當然不會有資料,所以要判斷一下! { pre->rightChild = node; } pre = node; threadTreeCreat(node->rightChild); return; } struct node* Tree::treeCreat(struct node* node) { char ch; cin >> ch; if (ch == '#') { node = NULL; } else { node = new struct node; node->data = ch; //node->ltag = (flag)0; node->rtag = (flag)0; node->leftChild = treeCreat(node->leftChild); node->rightChild = treeCreat(node->rightChild); } return node; } void Tree::destroyTree(struct node* node) { if (node == NULL) { return; } if (node->leftChild != NULL&&node->ltag == 0) { destroyTree(node->leftChild); } if (node->rightChild != NULL&&node->rtag == 0) { destroyTree(node->rightChild); } delete node; node = NULL; return; }