二叉树的定义:一棵二叉树t是有限个元素对集合(可以为空)。当二叉树非空时,其中一个元素称为根,余下的元素被划分成两棵二叉树,分别称为左子树和右子树。
二叉树的特性:
- 一棵二叉树有n个元素,他有n-1条边
- 一棵二叉树的高度为h,他最少有h个元素,最多有
个元素,此时称为满二叉树
- 一棵二叉树有n个元素,他的高度最大为n,最小高度为
二叉树的常见操作:
- 二叉树的节点结构
template<class T>
struct binaryTreeNode
{
T element;
binaryTreeNode<T> *left;
binaryTreeNode<T> *right;
binaryTreeNode(){left = right = NULL}
binaryTreeNode(const T& theElement)
{
element = theElement;
left = right = NULL;
}
binaryTreeNode(const T& theElement,binaryTreeNode *theLeft,binaryTreeNode*theRight)
{
element = theElement;
left = theLeft;
right = theRight;
}
};
二叉树的创建
template<class T>
void createBinaryTree(binaryTreeNode<T>* &root)
{
T ch;
cin>>ch;
if(ch == '#') root=NULL;
else
{
root = new binaryTreeNode<T>();
root->element = ch;
//递归创建
createBinaryTree(root->left);
createBinaryTree(root->right);
}
}
前序遍历(递归操作)
template<class T>
void preOrder(binaryTreeNode<T> *t)
{
if(t!=NULL)
{
cout<<t->element; //访问根节点
preOrder(t->left); //递归访问左子树
preOrder(t->right); //递归访问右子树
}
}
中序遍历(递归操作)
template<class T>
void inOrder(binaryTreeNode<T> *t)
{
if(t !=NULL)
{
inOrder(t->left); //递归遍历左子树
cout<<t->element; //访问根节点
inOrder(t->right); //递归遍历右子树
}
}
后序遍历(递归操作)
template<class T>
void postOrder(binaryTreeNode<T> *t)
{
if(t!=NULL)
{
postOrder(t->left); //递归遍历左子树
postOrder(t->right); //递归遍历右子树
cout<<t->element; //访问根节点
}
}
前序遍历(迭代解法)
//二叉树前序遍历(非递归解法)
template<class T>
void preOrder(binaryTreeNode<T>*root)
{
//先定义所需要的栈
stack<binaryTreeNode<T>*> myStack;
if(root == NULL)
return;
//先将根节点入栈
myStack.push(root);
while(!myStack.empty())
{
//既然是先序遍历,先将根弹栈,读取元素值
binaryTreeNode<T>* temp = myStack.top();
myStack.pop();
//输出当前根节点元素值
cout<<temp->element<<endl;
//将左节点入栈
if(temp->left !=NULL)
myStack.push(temp->left);
if(temp->right !=NULL)
myStack.push(temp->right);
}
}
中序遍历(迭代解法)
//二叉树中序遍历,非递归解法
template<class T>
void inOrder(binaryTreeNode<T>* root)
{
if(root == NULL)
return;
//定义栈
stack<binaryTreeNode<T>*> myStack;
binaryTreeNode<T>* current = root;
while(current !=NULL || !myStack.empty())
{
if(current)
{
myStack.push(current);
current = current->left;
}
else
{
current = myStack.top();
cout<<current->element<<endl;
myStack.pop();
current = current->right;
}
}
}
后序遍历(迭代解法)
//后序遍历,非递归解法,因为是先访问左子树,再访问右子树,最后访问根节点
//当用堆栈来存储节点,必须分清返回根节点时,是从左子树返回的还是从右子树返回
//的。所以,使用辅助指针pre,使其指向最近访问过的节点。亦可在节点中增加一个
//标志域,记录是否已经被访问
template<class T>
void postOrder(binaryTreeNode<T>* root)
{
if(root == NULL)
return;
//定义栈
stack<binaryTreeNode<T>*> myStack;
binaryTreeNode<T> *current = root;
binaryTreeNode<T> *pre = NULL;
while(current !=NULL || !myStack.empty())
{
if(current) //走到最左边
{
myStack.push(current);
current = current->left;
}
else
{
current = myStack.top();
if(current->right != NULL && current->right !=pre)//右子树存在,未被访问过
current = current->right;
else
{
myStack.pop();
//取值
cout<<current->element<<endl;
pre = current; //记录最近访问过的节点
current = NULL; //节点访问完之后,重置current
}
}
}
}
层次遍历:在层次遍历中,从顶层到底层,在同一层中,从左到右,依次访问树的元素。因为层次遍历中需要的数据结构是队列而不是栈,故层次遍历中不好写出递归程序。
template<class T>
void levelOrder(binaryTreeNode<T> *t)
{
//首先需要构建层次遍历需要的队列
queue<binaryTreeNode<T>*> q;
while(t!=NULL)
{
count<<t->element; //访问根元素
if(t->left !=NULL)
q.push(t->left);
if(t->right !=NULL)
q.push(t->right);
//出队
t = q.front();
q.pop();
}
}
确定二叉树的高度(递归实现)
template<class T>
int heightOfBinaryTree(binaryTreeNode<T> *t)
{
if(t==NULL)
return 0;
else
{
int leftH = heightOfBinaryTree(t->left);
int rightH = heightOfBinaryTree(t->right);
if(leftH > rightH)
return ++leftH;
else
return ++rightH;
}
}
确定二叉树的最小深度(递归实现)
template<class T>
int getMinDepth(binaryTreeNode<T> *t)
{
if(t==NULL)
return 0;
if(t->left == NULL || t->right == NULL)
return 1;
int hl = getMinDepth(t->left);
int hr = getMinDepth(t->right);
if(hl<hr)
return ++hl;
else
return ++hr;
}
确定二叉树中节点的个数
template<class T>
int numOfTreeNode(binaryTreeNode<T> *t)
{
if(t==NULL)
return 0;
int numOfLeft = numOfTreeNode(t->left); //左子树节点个数
int numOfRight = numOfTreeNode(t->right); //右子树节点个数
return numOfLeft+numOfRight+1; //左子树节点个数+右子树节点个数+根节点
}
确定二叉树中叶子节点的个数
template<class T>
int numOfLeafNode(binaryTreeNode<T> *t)
{
if(t == NULL)
return 0;
if(t->left == NULL && t->right == NULL)
return 1;
return numOfLeafNode(t->left) + numOfLeafNode(t->right);
}
求二叉树中第K层节点的个数
template<class T>
int numOfkLevelTreeNode(binaryTreeNode<T> *t,int k)
{
if(t == NULL || k<1)
return 0;
if(k==1)
return 1;
int numLeft = numOfkLevelTreeNode(t->left,k-1);
int numRight = numOfkLevelTreeNode(t->right,k-1);
return numLeft+numRight;
}
判断二叉树是否是平衡二叉树
template<class T>
bool isBalancedTreeNode(binaryTreeNode<T> * t)
{
if(t == NULL)
return true;
if(t->left == NULL && t->right == NULL)
return true;
int leftH = heightOfBinaryTree(t->left); //记录左子树高度(该函数前面已经实现)
int rightH = heightOfBinaryTree(t->right); //记录右子树高度
if((leftH -rightH)>=-1 && (leftH-rightH)<=1 )
return true;
else
return false;
return isBalancedTreeNode(t->left) && isBalancedTreeNode(t->right);
}
判断二叉树是否是完全二叉树
//判断是否是完全二叉树
/*对于一颗完全二叉树采用广度优先遍历,从根节点开始,入队列
如果队列不为空,循环。遇到第一个没有左儿子或者右儿子的节
点,设置标志位,如果之后再遇到有左/右儿子的节点,那么这不
是一颗完全二叉树。这个方法需要遍历整棵树,复杂度为O(N),
N为节点的总数。*/
template<class T>
bool isCompleteTreeNode(binaryTreeNode<T> *t)
{
if(t == NULL)
return false;
queue<binaryTreeNode<T>*> myQueue;
myQueue.push(t);
bool result = true;
bool hasNoChild = false;
while(!myQueue.empty())
{
binaryTreeNode* current = myQueue.front();
myQueue.pop();
if(hasNoChild) //如果没有孩子节点
{
if(current->left !=NULL || current->right !=NULL)
{
result = false;
break;
}
}
else //如果有孩子节点
{
if(current->left !=NULL && current->right !=NULL)
{
myQueue.push(current->left);
myQueue.push(current->right);
}
else if(current->left !=NULL && current->right == NULL)
{
myQueue.push(current->left);
hasNoChild = true;
}
//如果只有一个节点,那肯定是只有左节点
else if(current->left == NULL && current->right !=NULL)
{
result = false;
break;
}
else
{
hasNoChild = true;
}
}
}
return result;
}
判断两棵二叉树是否完全相同
bool isSameTreeNode(binaryTreeNode *t1,binaryTreeNode *t2)
{
if(t1 == NULL && t2 == NULL)
return true;
else if(t1 == NULL || t2 == NULL)
{
return false;
}
if(t1->element != t2->element)
return false;
//递归判断两棵树的左右子树是否都相等
bool left = isSameTreeNode(t1->left,t2->left);
bool right = isSameTreeNode(t1->right,t2->right);
return left && right;
}
看两棵二叉树是否互为镜像
template<class T>
bool isMirror(binaryTreeNode<T>*t1,binaryTreeNode<T>*t2)
{
if(t1 == NULL && t2 == NULL)
return true;
else if(t1 ==NULL || t2 == NULL)
return false;
if(t1->element !=t2->element)
return false;
bool M1 = isMirror(t1->left,t2->right);
bool M2 = isMirror(t1->right,t2->left);
return M1&&M2;
}
镜像二叉树(反转二叉树)
//镜像二叉树 或者叫翻转二叉树
template<class T>
binaryTreeNode<T>* mirrorTreeNode(binaryTreeNode<T>* root)
{
if(root == NULL)
return NULL;
binaryTreeNode<T>* l = mirrorTreeNode(root->left);
binaryTreeNode<T>* r = mirrorTreeNode(root->right);
root->left = r;
root->right = l;
return root;
}
求两个二叉树的最低公共祖先节点
template<class T>
binaryTreeNode<T>* getLastCommonParent(binaryTreeNode<T>*root,binaryTreeNode<T>*t1,binaryTreeNode<T>*t2)
{
if(findNode(root->left,t1))
{
if(findNode(root->right,t2))
return root;
else
return getLastCommonParent(root->left,t1,t2);
}
else
{
if(findNode(root->left,t2))
{
return root;
}
else
{
return getLastCommonParent(root->right,t1,t2);
}
}
}
//查找当前节点node是否在二叉树中
bool findNode(binaryTreeNode<T> * root, binaryTreeNode<T>*node)
{
if(root == NULL || node ==NULL)
return false;
if(root == node)
return true;
bool found = findNode(root->left,node);
if(!found)
found = findNode(root->right,node);
return found;
}
在二叉树中插入节点
//在二叉树中插入节点
template<class T>
binaryTreeNode<T> * insert(binaryTreeNode<T>*root, binaryTreeNode<T>*node)
{
if(root == node)
return root;
binaryTreeNode<T>* temp = root;
binaryTreeNode<T>* last = NULL;
while(temp!=NULL)
{
last = temp;
if(temp->element > node->element)
{
temp = temp->left;
}
else
{
temp = temp->right;
}
}
if(last != NULL)
{
if(last->element > node->element)
{
last->left = node;
}
else
{
last->right = node;
}
}
return root;
}
输入一个二叉树和整数,打印出二叉树中节点值的和等于输入整数的所有路径
void findTreePath(binaryTreeNode<int>*root,int i)
{
if(root == NULL)
return ;
stack<int> myStack;
int currentSum = 0;
findPath(root,i,myStack,currentSum);
}
void findPath(binaryTreeNode<int>*root, int i,stack<int>& myStack, int& currentSum)
{
currentSum += root->element;
myStack.push(root->element);
if(root->left == NULL && root->right == NULL)
{
if(currentSum == i)
{
while(!myStack.empty())
{
cout<<myStack.top()<<endl;
myStack.pop();
}
}
}
if(root->left !=NULL)
{
findPath(root->left,i,myStack,currentSum);
}
if(root->right !=NULL)
{
findPath(root->right,i,myStack,currentSum);
}
myStack.pop();
}
二叉树的搜索区间:给定两个值 k1 和 k2(k1 < k2)和一个二叉查找树的根节点。找到树中所有值在 k1 到 k2 范围内的节点。即打印所有x (k1 <= x <= k2) 其中 x 是二叉查找树的中的节点值。返回所有升序的节点值
vector<int> searchHelper(binaryTreeNode<int>*root, int k1,int k2)
{
if(root == NULL)
return;
vector<int> result;
if(root->element>=k1 && root->element<=k2)
{
result.push_back(root->element);
}
if(root->element >k1)
{
searchHelper(root->left,k1,k2);
}
if(root->element <k2)
{
searchHelper(root->right,k1,k2);
}
return result;
}
判断一棵二叉树是否为合法的BST(二叉查找树)
一棵BST定义为:
节点的左子树中的值要严格小于该节点的值。
节点的右子树中的值要严格大于该节点的值。
左右子树也必须是二叉查找树。
一个节点的树也是二叉查找树
bool isBST(binaryTreeNode<int> *root)
{
if(root == NULL)
return true;
int numLeft = root->left->element;
int numRight = root->right->element;
if(root->element>numLeft && root->element<numRight)
{
return isBST(root->left)&& isBST(root->right);
}
else
{
return false;
}
}