結點的構造
#pragma once #ifndef NODE_H #define NODE_H class Node { public: Node(); Node *SearchNode(int nodeIndex); void DeleteNode(); void PreorderTraversal(); void InorderTraversal(); void PostorderTraversal(); int index; int data; Node *pLChild; Node *pRChild; Node *pParent; }; #endif // !NODE_H
需要實現的方法
#pragma once #ifndef TREE_H #define TREE_H #include"Node.h" class Tree { public: Tree();//創建樹 ~Tree();//銷毀樹 Node *SearchNode(int nodeIndex);//搜索結點 bool AddNode(int nodeIndex, int direction, Node* pNode);//添加結點 bool DeleteNode(int nodeIndex, Node* pNode);//刪除結點 void PreorderTraversal();//前序遍歷 void InorderTraversal();//中序遍歷 void PostorderTraversal();//后序遍歷 private: Node * m_pRoot; }; #endif // ! TREE_H
創建樹
申請一段內存
Tree::Tree() { m_pRoot = new Node(); };
創建結點
Node::Node() { index = 0; data = 0; pLChild = NULL; pRChild = NULL; pParent = NULL; }
銷毀樹
調用Node的DeleteNode方法
Tree::~Tree() { m_pRoot->DeleteNode(); }
如果當前Node對象(this)的pLChild不為空,遞歸調用DeleteNode方法,this->pLChild變成了新的this,直到delete this銷毀掉
如果當前Node對象(this)的pRChild不為空,遞歸調用DeleteNode方法,this->pRChild變成了新的this,直到delete this銷毀掉
如果當前Node對象(this)的pParent不為空,如果父節點的左子節點等於當前Node對象,將當前結點置空
如果當前Node對象(this)的pParent不為空,如果父節點的右子節點等於當前Node對象,將當前結點置空
思路:指定索引向下搜索從最底層子節點開始刪除,再往上回到指定索引並刪除,刪除的順序是后序
void Node::DeleteNode() { if (this->pLChild != NULL) { this->pLChild->DeleteNode(); } if (this->pRChild != NULL) { this->pRChild->DeleteNode(); } if (this->pParent != NULL) { if (this->pParent->pLChild == this) { this->pParent->pLChild = NULL; } if (this->pParent->pRChild == this) { this->pParent->pRChild = NULL; } } delete this; }
搜索結點
傳入索引,調用Node的SearchNode方法
Node *Tree::SearchNode(int nodeIndex) { return m_pRoot->SearchNode(nodeIndex); }
Node的SearchNode()
如果索引和傳入索引相等,返回當前Node對象
當this對象的左子節點不為空,當左子節點索引等於傳入索引,返回當前對象的子節點
否則繼續對當前對象的左子節點搜索,搜索結果賦值給temp,當temp不為空,返回temp
對右子節點的邏輯同上
否則返回為空
思路:從上向下搜索,順序為前序
Node *Node::SearchNode(int nodeIndex) { if (this->index == nodeIndex) { return this; } Node *temp = NULL; if (this->pLChild != NULL) { if (this->pLChild->index == nodeIndex) { return this->pLChild; } else { temp = this->pLChild->SearchNode(nodeIndex); if (temp != NULL) { return temp; } } } if (this->pRChild != NULL) { if (this->pRChild->index == nodeIndex) { return this->pRChild; } else { temp = this->pRChild->SearchNode(nodeIndex); if (temp != NULL) { return temp; } } } return NULL; }
添加結點
傳入索引,direction=0添加左子節點,direction=1添加右子節點,傳入pNode參數
先搜索結點並保存在temp中,temp為空返回錯誤
申請內存給node,為空返回錯誤
將pNode的index和data分別賦值給node的index和data
node的pParent指針指向temp,temp為指定索引的父節點
direction=0,將temp的pLChild指針指向node
direction=1,將temp的pRChild指針指向node
bool Tree::AddNode(int nodeIndex, int direction, Node* pNode) { Node *temp = SearchNode(nodeIndex); if (temp == NULL) { return false; } Node *node = new Node(); if (node == NULL) { return false; } node->index = pNode->index; node->data = pNode->data; node->pParent = temp; if (direction == 0) { temp->pLChild = node; } if (direction == 1) { temp->pRChild = node; } return true; }
刪除結點
傳入nodeIndex,pNode參數
搜索結點保存在temp
temp為空,返回錯誤
pNode不為空,將的temp的data賦值給pNode的data,做返回值使用
調用Node的DeleteNode方法,參見銷毀樹
bool Tree::DeleteNode(int nodeIndex, Node* pNode) { Node *temp = SearchNode(nodeIndex); if (temp == NULL) { return false; } if (pNode != NULL) { pNode->data = temp->data; } temp->DeleteNode(); return true; }
前序遍歷
調用了Node的PreorderTraversal()
void Tree::PreorderTraversal() { m_pRoot->PreorderTraversal(); }
Node的PreorderTraversal()
先輸出根節點
左子結點不為空遞歸,輸入當前結點
右子節點不為空遞歸,輸入當前結點
遞歸的算法最好對着源碼打斷點,就能看懂了
void Node::PreorderTraversal() { cout << this->index<<" "<<this->data << endl; if (this->pLChild != NULL) { this->pLChild->PreorderTraversal(); } if (this->pRChild != NULL) { this->pRChild->PreorderTraversal(); } }
中序遍歷和后序遍歷
中序遍歷:左根右
后序遍歷:左右根
void Tree::InorderTraversal() { m_pRoot->InorderTraversal(); } void Tree::PostorderTraversal() { m_pRoot->PostorderTraversal(); }
邏輯與前序遍歷代碼相似
this->index和this->data就是根節點的內容
左右結點進行遞歸
void Node::InorderTraversal() { if (this->pLChild != NULL) { this->pLChild->InorderTraversal(); } cout << this->index << " " << this->data << endl; if (this->pRChild != NULL) { this->pRChild->InorderTraversal(); } } void Node::PostorderTraversal() { if (this->pLChild != NULL) { this->pLChild->PostorderTraversal(); } if (this->pRChild != NULL) { this->pRChild->PostorderTraversal(); } cout << this->index << " " << this->data << endl; }
補充
根據前序和中序推斷出二叉的結構
前序遍歷為ABDEGCFH
后序遍歷為DBGEACHF