二叉树的基本操作
2017-04-29 13:40
369 查看
百度百科:二叉树
刷题是学习数据结构,整理自己的思路最快的方法。所以推荐大家多思考,人人都会敲代码,但是思路不一定每个人都会有。
1.求一个结点的父节点
2.求结点的左兄弟结点或右兄弟结点
3.求一颗二叉树的高度
4.求结点i的深度
5.根据一颗二叉树的前序和中序重建一棵二叉树
如果我当前结点的左孩子或者右孩子等于遍历查找返回的结点,那么那么我们就返回结点。
方法二:跟父节点有关系的,我们还可以想到层序遍历,如果左右孩子不为空,就将其左右孩子结点入队。在入之前我们可以进行判断,如果相等,我们就将其父结点返回.
思路1.递归法**
思路:先求其左子树的高度,再求其右子树的高度,取其较高者,就是该树的高度
思路二:遍历法
一直走到根节点,更新最大长度,循环结束后,即可得该树的高度。
这里为了更好的理解:后序遍历的非递归方式,这里我们用后序遍历来解决这个问题,注意我们的flagStack.就是来区分前中后序遍历的。
其余基本操作完整代码:
刷题是学习数据结构,整理自己的思路最快的方法。所以推荐大家多思考,人人都会敲代码,但是思路不一定每个人都会有。
题目
主要问题1.求一个结点的父节点
2.求结点的左兄弟结点或右兄弟结点
3.求一颗二叉树的高度
4.求结点i的深度
5.根据一颗二叉树的前序和中序重建一棵二叉树
1.求一个结点的父结点
方法一:我们知道,二叉树的相关操作无非就是,几种遍历方式,然后进相应的操作即可,那么首先想到的就是递归遍历。如果我当前结点的左孩子或者右孩子等于遍历查找返回的结点,那么那么我们就返回结点。
Node* _Parent(Node* root ,Node * cTest) { if (root == NULL) { return NULL; } if (root->_pLeft == NULL&&root->_pRight == NULL) { return NULL; } if (root->_pLeft == cTest||root->_pRight==cTest) { return root; } Node* parent= _Parent(root->_pLeft, cTest); if (parent) { return parent; } return _Parent(root->_pRight,cTest); }
方法二:跟父节点有关系的,我们还可以想到层序遍历,如果左右孩子不为空,就将其左右孩子结点入队。在入之前我们可以进行判断,如果相等,我们就将其父结点返回.
Node* ParentNode(Node * node) { if (node == NULL || _pRoot == node) { return NULL; } int max = 50; int front, rear; Node* current, *child; int count = 0; if (node != NULL) { Node* queue[max]; front = rear = 0; queue[rear++] = node; count++; while (count != 0) { current = queue[front]; if (current->_pLeft) { child = current->_pLeft; if (node == child) { return current; } else { //入队 queue[rear] = child; rear = (rear + 1)%max;//循环队列实现方式 count++; } } if (current->_pRight) { child = current->_pRight; if (child == node) { return current; } else { queue[rear] = child; rear = (rear + 1) % max; count++; } } front = (front + 1) % max;//出队 count--; } } return NULL; }
2.求结点的左兄弟结点或右兄弟结点
思路:找到父节点后(第一题),其兄弟结点很容易知道,不再累赘。3.求一颗二叉树的高度
**两种实现方式:思路1.递归法**
思路:先求其左子树的高度,再求其右子树的高度,取其较高者,就是该树的高度
size_t _Height(Node* root) { //左右子树最深的个数加1就是当前树的深度 if (root == NULL) { return 0; } size_t left = _Height(root->_pLeft); size_t right = _Height(root->_pRight); return left > right ? left + 1 : right + 1; }
思路二:遍历法
一直走到根节点,更新最大长度,循环结束后,即可得该树的高度。
template<typename DataType> size_t BinaryTree<DataType>::getDepth(int numberofNodes) { BinaryTreeNode<DataType>* nodeStack = new BinaryTreeNode<DataType>[numberofNodes];//设置存储二叉树结点的栈 int depthStak[numberofNodes];//声明深度栈 int currentDepth, maxDepth = 0; int top = -1; BinaryTreeNode<DataType>*node = root; if (node != NULL) { currentDepth = 1;//高度从0开始计数 do { while (node != NULL) { nodeStack[++top] = node;//M模拟栈这样的使用top,当取的时候非常方便 node = node->lChild; depthStack[top] = currentDepth; currentDepth++; } node = nodeStack[top]; currentDepth = depthStack[top--];//出栈,并且取出上一步的高度 if (node->lChild == NULL&&node->rChild == NULL) { if (currentDepth > maxDepth) { maxDepth = currentDepth; } } node = node->rChild; currentDepth++; } while (!(node == NULL&&top == -1)); } return maxDepth; }
4.求结点i的深度
思路:纵观这些题,我们可以知道无非就是就是遍历只是操作和返回的东西不一样,根据栈的性质进行前进或者回溯不断缩小问题规模。所以就会有两种方法:递归和非递归这里为了更好的理解:后序遍历的非递归方式,这里我们用后序遍历来解决这个问题,注意我们的flagStack.就是来区分前中后序遍历的。
template<typename DataType> int BinaryTree<DataType>::getDepthofNode(DataType i) { int stackSize = 0; BinaryTreeNode<DataType>* nodeStack[stackSize]; int flagStack[StackSize];//存储每个结点的状态 int flag = 0; int top = -1; BinaryTreeNode<DataType>* node = root; do{ while (node != NULL) { nodeStack[++top] = node; flagStack[top] = 0; node = node->_pLeft; } node = nodeStack[top]; flag = flagStack[top--]; if (flag = 0) { nodeStack[++top] = node;//将第一次访问的结点再次入栈 flagStack[top] = 1; node = node->rChild; } else { if (node->_data == i) { return top + 2; } node = NULL; } } while (!(node==NULL&&top==-1)) }
5.根据一颗二叉树的前序和中序重建一棵二叉树
根据二叉树遍历的性质,我们可以知道前序的第一个结点是根结点,据此,我们就可以把中序遍历的结果分为两份,一份左半子树,一份右半子树。void ReBuild(char*pPreOrder, char* pInorder, int nTreeLen, Node**pRoot) { //检查边界 if (pPreOrder == NULL || pInOrder == NULL) { return; } Node* temp = new Node; temp->data = *pPreOrder; if (pRoot == NULL) { *pRoot = temp; } if (nTreeLen == 1) { return; } char* pOrgInOrder = pInOrder; char* pLeftEnd = pInOrder; int nTempLen = 0; while (*pPreOrder != *pLeftEnd) { if (pPreOrder == NULL || pLeftEnd == NULL) return; nTempLen++; if (nTempLen > nTreeLen)break; pLeftEnd++; } int nLeftLen = (int)(pLeftEnd - pOrgInOrder); int nRightLen = nTreeLen - nLeftLen - 1; if (nLeftLen > 0) { ReBuild(pPreOrder + 1, pInOrder, nLeftLen, &((*pRoot)->left)); } if(nRightLen > 0) { ReBuild(pPreOrder + nLeftLen + 1, pInOrder + nLeftLen + 1, nRightLen, &((*pRoot)->right)); } }
其余基本操作完整代码:
#include<iostream> #include<queue> #include<assert.h> using namespace std; //二叉树的构建、销毁、赋值,拷贝构造。、遍历、修改、查找、 template<typename T> struct BinaryTreeNode { BinaryTreeNode<T>(const T&data=T()) : _data(data) , _pLeft(NULL) , _pRight(NULL) {} T _data; BinaryTreeNode<T>* _pLeft; BinaryTreeNode<T>*_pRight; }; template<typename T> class BinaryTree { typedef BinaryTreeNode<T> Node; public: BinaryTree() :_pRoot(NULL) , _invalid(T()) { } BinaryTree(const T arr[], const size_t length,const T& invalid) { size_t index = 0; _pRoot = _CreateTree(_pRoot, arr, length, index,invalid); } //前序遍历 void PreOrder() { _PreOrder(_pRoot); } void InOrder() { _InOrder(_pRoot); } void MidOrder() { _MidOrder(_pRoot); } void LevelOrder() { //层序遍历 //利用队列实现因为需要先入的先访问,如果按照栈的特点来做,访问左孩子后,为了方便访问下一层,需要保存它的左右孩子,无法访问按层序访问右孩子,因为已经插上来了 //所以我们使用队列,就可以满足这一点 //只需要一个循环就能实现 if (_pRoot != NULL) { queue<Node*>q; q.push(_pRoot); while (!q.empty()) { Node*cur = q.front(); q.pop(); cout << cur->_data<<" "; if (cur->_pLeft) { q.push(cur->_pLeft); } if (cur->_pRight) { q.push(cur->_pRight); } } } } //拷贝构造函数 BinaryTree(const BinaryTree<T>& Bt) { //根据指针拷贝对象 _pRoot = _Copy(Bt._pRoot); } //赋值函数 BinaryTree<T>* operator =(BinaryTree<T>Bt) { //基本框架一样 或者采用新赋值方法,交换两者的空间。然后函数结束,销毁临时对象 if (_pRoot != &Bt._pRoot) { //拷贝 BinaryTree<T> temp(Bt); Destory(_pRoot); //释放新空间 _pRoot = temp._pRoot; } return *this; } //查找 Node* Find(const T& t) { return _Find(_pRoot, t); } //找出该节点的父亲结点 //思路: //求叶子节点的个数 Node* Parent(Node* cTest) { return _Parent(_pRoot,cTest); } Node* _Parent(Node* root ,Node * cTest) { if (root == NULL) { return NULL; } if (root->_pLeft == NULL&&root->_pRight == NULL) { return NULL; } if (root->_pLeft == cTest||root->_pRight==cTest) { return root; } Node* parent= _Parent(root->_pLeft, cTest); if (parent) { return parent; } return _Parent(root->_pRight,cTest); } //求一个节点的父亲结点—方法二 //利用层序遍历(这一次我们自己实现一个队列)的思路如果结点等于其左子树或者右子树,将其返回 Node* ParentNode(Node * node) { if (node == NULL || _pRoot == node) { return NULL; } int max = 50; int front, rear; Node* current, *child; int count = 0; if (node != NULL) { Node queue[max]; front = rear = 0; queue[rear++] = node; count++; while (count != 0) { current = queue[front]; if (current->_pLeft) { child = current->_pLeft; if (node == child) { return current; } else { //入队 queue[rear] = child; rear = (rear + 1)%max;//循环队列实现方式 count++; } } if (current->_pRight) { child = current->_pRight; if (child == node) { return current; } else { queue[rear] = child; rear = (rear + 1) % max; count++; } } front = (front + 1) % max; count--; } } return NULL; } //求数的高度 size_t Height() { return _Height(_pRoot); } //节点个数 size_t size() { size_t count = 0; _size(_pRoot,count); return count; } //叶子节点个数 size_t leaf() { size_t count = 0; _leaf(_pRoot,count); return count; } ~BinaryTree() { //销毁函数 DestoryTree(_pRoot); _pRoot = NULL; } protected: //递归创建是一个二叉树 //Node*_CreateTree(Node* pRoot, const T arr[], const size_t length, size_t & index,const T &invalid) //{ // if (pRoot == NULL) // { // if (index < length&&arr[index] != invalid) // { // pRoot = new Node(arr[index]); // } // } // if (pRoot) // { // _CreateTree(pRoot->_pLeft, arr, length, ++index, invalid); // _CreateTree(pRoot->_pRight, arr, length, ++index, invalid); // } // return pRoot; //} Node* _CreateTree(Node* &pRoot,const T arr[],const size_t length,size_t&index,const T&invalid) { Node* temp = NULL; if (index<length&&arr[index]!=invalid)//pRoot为空不能作为遍历结束条件 { //先对根进行操作 temp = new Node(arr[index]); pRoot = temp; _CreateTree(pRoot->_pLeft, arr, length, ++index, invalid);//在遍历左子树 _CreateTree(pRoot->_pRight, arr, length, ++index, invalid);//在遍历右子树 } return temp; } //四种遍历:前中后。层 void _PreOrder(Node* pRoot) { if (pRoot) { cout << pRoot->_data << " "; _PreOrder(pRoot->_pLeft); _PreOrder(pRoot->_pRight); } } void _InOrder(Node* pRoot) { if (pRoot) { _InOrder(pRoot->_pLeft); _InOrder(pRoot->_pRight); cout << pRoot->_data << " "; } } void _MidOrder(Node* pRoot) { if (pRoot) { _PreOrder(pRoot->_pLeft); cout << pRoot->_data << " " << endl; _PreOrder(pRoot->_pRight); } } //拷贝构造函数 //Node* _Copy(Node* node) //{ // Node* cur = node; // Node* root = NULL; // if (cur) // { // root = new Node(cur->_data); // root->_pLeft = _Copy(cur->_pLeft); // root->_pRight = _Copy(cur->_pRight); // } // return root; // //} Node* _Copy(Node* node) { Node* root = NULL; if (node) { root = new Node(node->_data); root->_pLeft = _Copy(node->_pLeft); root->_pRight = _Copy(node->_pRight); } return root; } Node* _Find(Node* root, const T & t) { if (root) { if (root->_data == t) { return root; } Node* ret = _Find(root->_pLeft, t); //此处不应该如此,因为一直递归到最深处,假如没有找到,肯定函数返回为NULL,整个函数结束 if (ret) { return ret; } return _Find(root->_pRight, t); } return root; } size_t _Height(Node* root) { //左右子树最深的个数加1就是当前树的深度 if (root == NULL) { return 0; } size_t left = _Height(root->_pLeft); size_t right = _Height(root->_pRight); return left > right ? left + 1 : right + 1; } void _size(Node* root,size_t & count) { if (root) { if (root->_pLeft == NULL&&root->_pRight == NULL) { return; } _size(root->_pLeft, ++count); _size(root->_pRight, ++count); } } size_t _leaf(Node* root,size_t &count) { if (root == NULL) { return 0; } if (root->_pLeft == NULL&&root->_pRight == NULL) { count++; } _leaf(root->_pLeft, count); _leaf(root->_pRight, count); } //销毁函数 void DestoryTree(Node*pRoot) { if (pRoot) { DestoryTree(pRoot->_pLeft); DestoryTree(pRoot->_pRight); delete pRoot; pRoot = NULL; } } private: Node* _pRoot; T _invalid; }; void Test() { int arr[] = { 1,2, 4, '#', '#', '#', 3, 5, '#', '#', 6 }; BinaryTree<int> Bt(arr,sizeof(arr)/sizeof(arr[0]),'#'); //Bt.MidOrder(); //Bt.InOrder(); //Bt.PreOrder(); //Bt.LevelOrder(); /*BinaryTree<int> Bt1(Bt); Bt1.PreOrder(); cout << endl; BinaryTreeNode<int>* cur = Bt1.Find(6); cout << cur->_data << " ";*/ BinaryTreeNode<int>* cur = Bt.Find(6); BinaryTreeNode<int>*parent = Bt.Parent(cur); cout << parent->_data << endl; cout << "size::" << Bt.size() << " " << "Height::" << Bt.Height() << " Leaf::" << Bt.leaf() << endl; } int main() { Test(); return 0; }