定义
一棵二叉树t是有限个元素的几何(可以为空)。当二叉树非空时,其中有一个元素称为根,余下的元素(如果有的话)被划分为两棵二叉树,分别称为t的左子树和右子树。
特性
- 一棵二叉树有n个元素,n>0,它有n-1条边;
- 一棵二叉树的高度为h,h>=0,它最少有h个元素,最多有2^h-1个元素;
- 一棵二叉树有n个元素,n>0,它的最大高度为n,最小高度为[log(n+1)];
- 设完全二叉树的一个元素其编号为i,1<=i<=n。有以下关系成立:
1)如果i=1,则该元素为二叉树的根。若i>1,则其父节点的编号为[i/2];
2)如果2i>n,则该元素无左孩子。否则,其左孩子的编号为2i;
3)如果2i+1>n,则该元素无右孩子。否则,其右孩子的编号为2I+1。
链表描述
链表二叉树的节点结构
template<class T>
struct binaryTreeNode
{
T element;
binaryTreeNode<T>* leftChild;//左子树
binaryTreeNode<T>* rightChild;//右子树
binaryTreeNode(){leftChild=rightChild=null}
binaryTreeNode(const T& theElement)
{
element(theElement)
leftChild=rightChild=null;
}
binaryTreeNode(const T& theElement,binaryTreeNode* theLeftChild,binaryTreeNode* theRightChild)
{
element(theElement)
leftChild=theLeftChild;
rightChild=theRightChild;
}
}
二叉树遍历
有4种遍历二叉树的常用方法:
- 前序遍历
- 中序遍历
- 后序遍历
- 层次遍历
前序遍历
template <class T>
void preOrder(binaryTreeNode<T> *t)
{
if(t!=nullptr)
{
visit(t);//访问树根
preOrder(t->leftChild);//前序遍历左子树
preOrder(t->rightChild);//前序遍历右子树
}
}
中序遍历
template <class T>
void inOrder(binaryTreeNode<T> *t)
{
if(t!=nullptr)
{
inOrder(t->leftChild);//中序遍历左子树
visit(t);//访问树根
inOrder(t->rightChild);//中序遍历右子树
}
}
后序遍历
template <class T>
void postOrder(binaryTreeNode *t)
{
postOrder(t->leftChild);//后序遍历左子树
postOrder(t->rightChild);//后序遍历右子树
visit(t);//访问树根
}
层次遍历
template<class T>
void levelOrder(binaryTreeNode<T> *t)
{
arrayQueue<binaryTreeNode<T>*> q;
while(t!=nullptr)
{
visit(t);//访问树根
if(t->leftChild!=null)
q.push(t->leftChild);
if(t->rightChild!=null)
q.push(t->leftChild);
}
try{t=q.front();}
catch(queueEmpty)
{return 0;}
q.pop();
}
visit函数
template<class T>
void visit(binaryTreeNode<T>* x)
{
cout<<x->element<<' ';
}
复杂度分析
设一棵二叉树有n个元素。这四种遍历算法的空间和时间复杂度都是O(n)。
1. 空间需求:
1)高度为n时。前序、中序和后序的所需的递归栈空间是O(n)。
2)满二叉树时,层次遍历所需的队列空间为O(n)
2. 时间需求:假设访问一个节点时间是O(1),每一个遍历花在一个节点上的时间为O(1)