您的位置:首页 > 其它

二叉树的基本操作

2017-04-29 13:40 369 查看
百度百科:二叉树

刷题是学习数据结构,整理自己的思路最快的方法。所以推荐大家多思考,人人都会敲代码,但是思路不一定每个人都会有。

题目

主要问题

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: