近日准备找工作,看了数据结构相关内容,在这里总结一下二叉树的相关操作,以示勉励。有更好的实现算法,希望大家一起分享。
PS.今天早上同学收到华为offer,下午去签约了,我比他晚一天面试,希望明天能有好的运气。
闲话不多说,直接上代码。
#include <iostream>
#include <stdlib.h>
#include <queue>
#define TRUE 1
#define FALSE 0
using namespace std;
typedef int ElementType;//二叉树节点元素类型
/**
*二叉查找树节点定义
**/
struct TreeNode
{
ElementType data;
struct TreeNode *left;
struct TreeNode *right;
};
typedef struct TreeNode* Tree;
以上是本文用到的一些宏定义以及树节点定义。本文所有函数都通过Visual Studio 2010测试。
1.
/**
*创建一棵空的树
**/
Tree CreateEmptyTree(void)
{
Tree tree = (Tree)malloc(sizeof(struct TreeNode)); //这里动态分配了内存,一定要记得在某个地方释放内存,并置tree = NULL
if(NULL==tree)
{
cout<<"Failed in Create Empty Tree"<<endl;
return NULL;
}
tree->left = NULL;
tree->right = NULL;
return tree;
}
2.
/**
*往树中插入一个新元素,如果元素重复,则不插入
**/
Tree Insert(ElementType x,Tree tree)
{
if(NULL==tree) //判断树是否为空
{
tree = CreateEmptyTree(); //为空,创建树
if(NULL == tree)
{
cout<<"Insert tree failed!"<<endl;
}
else
{
tree->data = x; //将新元素插入新创建的空树
//这一步个人觉得可有可无,以为在CreateEmptyTree()中已经设定这个节点的左右子节点为NULL了。
tree->left = tree->right = NULL;
}
}
else
{
if(x<tree->data)
tree->left = Insert(x,tree->left); //如果元素小于根节点,插入树的左边
else if(x>tree->data)
tree->right = Insert(x,tree->right);//如果元素大于根节点,插入树的右边
}
return tree;
}
3.
/** *根据数组元素创建树 *这里创建的树为二叉查找树 *len为数据元素个数**/ Tree CreateTreeByArray(ElementType * pArr,int len) { Tree tree = CreateEmptyTree(); //首先创建空树 int i; if(tree!=NULL) { tree->data = pArr[0]; //将数组首元素作为树根,如果数组首元素比较小,那么所创建的树的深度就会比较大 } for(i=1;i<len;i++) //将数组元素一次插入树中 { Insert(pArr[i],tree); } return tree; }
4.这个函数不用多说了。
/**
*访问节点元素
**/
void visit(ElementType x)
{
cout<<x<<" ";
}
5.
/**
*中序遍历树
**/
void inOrderTree(Tree tree)
{
if(NULL!=tree)
{
inOrderTree(tree->left);
visit(tree->data); //中序遍历就是先遍历左子树,再打印节点元素,最有遍历右子树
inOrderTree(tree->right);
}
}
6.前序编译就先打印根节点,然后在依次递归左右子树
/**
*前序遍历
**/
void prefixTree(Tree tree)
{
if(NULL!=tree)
{
visit(tree->data);
prefixTree(tree->left);
prefixTree(tree->right);
}
}
7.
/** *后序遍历
**/ void postTree(Tree tree) { if(NULL!=tree) { prefixTree(tree->left); prefixTree(tree->right); visit(tree->data); } }
8.
/**
*按层遍历树,原理是借用队列,
**/
void OrderTree(Tree tree)
{
queue<Tree> q;
if(NULL!=tree)
{
q.push(tree); //将树根节点进入队列
}
while(!q.empty()) //判断队列是否为空,不为空,去队列最前面的节点,这个节点可以找到它的左右子节点,然后分别将它的左右子节点进入队列
{
if(q.front()->left!=NULL) //队列最前面的节点是否有左子结点
q.push(q.front()->left);
if(q.front()->right!=NULL) //队列最前面的节点是否有右子结点
q.push(q.front()->right);
visit(q.front()->data); //输出队列最前面的节点
q.pop(); //将队列最前面的节点一处队列
}
}
9.从二叉查找树中找到最小节点,根据左子树所有节点都比右子树节点元素小的原理,先判断是否含有左子树,如果不含,那么节点就是最小元素,如果有左子树,那么就递归查找左子树中的最小元素
/**
*找到树中元素值最小的节点,返回该节点的指针
**/
Tree FindMin(Tree tree)
{
if(NULL==tree)
return NULL;
else if(tree->left==NULL)
{
return tree;
}
else
{
return FindMin(tree->left);
}
}
10.在二叉查找树中找到与元素x相同的节点,并返回该节点的指针
Tree FindFromTree(Tree tree,ElementType x)
{
if(tree==NULL)
return NULL;
else if(tree->data==x)//如果相等,直接返回
return tree;
else if(x < tree->data)//如果比当前节点小,那么从左子树中查找
return FindFromTree(tree->left,x);
else if(x>tree->data)//如果比当前节点大,那么从右子树中查找
return FindFromTree(tree->right,x);
}
11.
/**
*从树中删除与X相等的节点
*分两种情况:一,要删除的节点没有左右子树,二、含有子树
**/
Tree DeleteFromTree(ElementType X,Tree tree)
{
Tree tmpCell;
if(NULL==tree)
{
printf("Element %d not found\n",X);
}
else if(X < tree->data) //向左遍历找到要删除的节点
{
tree->left = DeleteFromTree(X,tree->left);
}
else if(X > tree->data) //向右遍历找到要删除的节点
{
tree->right = DeleteFromTree(X,tree->right);
}
/**
*如果当前节点即为要删除的节点,且左子树和右子树都不为空时,找到右子树中的最小元素,
*将该最小元素的值赋值给要删除的节点,即将要删除的节点转移动它的右子树的最小元素节点上,
*最后该最小元素删除,指针指向的内存释放。
**/
else if(tree->left && tree->right)
{
tmpCell = FindMin(tree->right); //
tree->data = tmpCell->data ; //
tree->right = DeleteFromTree(tree->data,tree->right);
}
else
{
tmpCell = tree;
if(tree->left == NULL)
{
tree = tree->right;
}
else if(tree->right == NULL)
{
tree = tree->left;
}
free(tmpCell);
}
return tree;
}
12.这个函数在13年威创视讯的笔试卷子上出现过
/**
*求树的深度
**/
int Hight(Tree tree)
{
if(tree==NULL)
return -1;
else
return 1+ max(Hight(tree->left),Hight(tree->right));
}
13.countLeaf的返回值以参数形式返回,
/**
*求树的叶子节点数目
**/
void countLeaf(Tree tree,int *count)
{
if(tree!=NULL)
{
if(tree->left!=NULL && tree->right!=NULL)
(*count)++;
countLeaf(tree->left,count);
countLeaf(tree->right,count);
}
}
14.先复制左右子树,在复制根节点,
/**
*树的复制
**/
Tree copyTree(Tree tree)
{
Tree newRoot,leftTree,rightTree;
if(tree==NULL)return NULL;
//if(tree->left!=NULL) //不能做这样的判断
leftTree = copyTree(tree->left);
//if(tree->right!=NULL)
rightTree = copyTree(tree->right);
newRoot = (Tree )malloc(sizeof(struct TreeNode));
if(!newRoot)
{
return NULL;
}
newRoot->data = tree->data;
newRoot->left = leftTree;
newRoot->right = rightTree;
return newRoot;
}
15.
/**
*删除树
**/
void DeleteTree(Tree tree)
{
if(tree!=NULL)
{
DeleteTree(tree->left);
DeleteTree(tree->right);
free(tree);
}
}
void clearTree(Tree &tree)
{
DeleteTree(tree);
tree=NULL; //这行代码很重要的,如果不置为NULL,就容易产生野指针
}
16.统计二叉树中的元素个数,这里给出了两种方法,分别用不同的返回方式放回结果
/**
*二叉树元素个数
**/
void size(Tree tree,int *_size)
{
if(tree!=NULL)
{
(*_size)++;
size(tree->left,_size);
size(tree->right,_size);
}
}
int treeSize(Tree tree)
{
int count = 0;
if(tree==NULL)return 0;
else
{
count = treeSize(tree->left) + treeSize(tree->right) + 1;
}
return count;
}
17.
/**
*判断一棵树是否为空
**/
int empty(Tree tree)
{
if(treeSize(tree)==0)
return TRUE;
else
return FALSE;
}