一.二叉树的存储结构
1. 顺序存储结构,最适合于完全二叉树,用于存储一般二叉树会浪费大量存储空间
2.链式存储结构
typedef struct BTNode
{
char data;
struct BTNode *lchild;
struct BTNode *rchild;
}BTNode;
二.二叉树的遍历算法
1.先序遍历(递归以及非递归)
void preOrder(BTNode *p)
{// 根--左--右
if(p != NULL)
{
Visit(p); //假设访问函数Visit()已经定义过,包含对结点p的各种访问操作
preOrder(p->lchild); //先序遍历左子树
preOrder(p->rchild); //先序遍历右子树
}
}
void preOrderNonRecursion(BTNode *bt)
{
if(bt != NULL)
{
BTNode * Stack[maxSize]; //定义一个栈
int top = -1; //初始化栈
BTNode *p;
Stack[++top] = bt;
while(top != -1)
{
p = Stack[top--]; //出栈并输出栈顶结点
Visit(p);
//先右后左
if(p->rchild != NULL) //栈顶结点的右孩子存在,则右孩子入栈
Stack[++top] = p->rchild;
if(p->lchild != NULL) //栈顶结点的左孩子存在,则左孩子入栈
Stack[++top] = p->lchild;
}
}
}
2.中序遍历(递归以及非递归)
void inOrder(BTNode *p)
{// 左--根--右
if(p != NULL)
{
inOrder(p->lchild);
Visit(p);
inOrder(p->rchild);
}
}
void inOrderNonRecursion(BTNode *bt)
{ //循环执行如下操作:如果栈顶结点左孩子存在,则左孩子入栈;
//如果栈顶结点左孩子不存在,则出栈并输出栈顶结点,
//然后检查其右孩子是否存在,如果存在,则右孩子入栈
if(bt != NULL)
{
BTNode *Stack[maxSize];
int top = -1;
BTNode *p;
p = bt;
while(top != NULL || p!= NULL)
{
while(p != NULL) //左孩子存在,则左孩子入栈
{
Stack[++top] = p;
p = p->lchild;
}
if(top != -1) //在栈不空的情况下出栈并输出栈结点
{
p = Stack[top--];
Visit(p);
p = p->rchild;
}
}
}
}
3.后序遍历(递归以及非递归)
void postOrder(BTNode *p)
{ //左--右--根
if(p != NULL)
{
postOrder(p->lchild);
postOrder(p->rchild);
Visit(p);
}
}
void postOrderNonRecursion(BTNode *bt)
{
if(bt != NULL)
{
//定义两个栈
BTNode *Stack1[maxSize];
int top1 = -1;
BTNode *Stack2[maxSize];
int top2 = -1;
BTNode *p = NULL;
Stack1[++top1] = bt;
while(top1 != -1)
{
p = Stack1[top1--];
Stack2[++top2] = p; //注意这里与先序遍历区别,输出改为入Stack2
//先左后右
if(p->lchild != NULL)
Stack1[++top1] = p->lchild;
if(p->rchild != NULL)
Stack1[++top1] = p->rchild;
}
while(top2 != -1)
{
//出栈序列即为后序遍历序列
p = Stack2[top2--];
Visit(p);
}
}
}
3.
int comp(BTNode *p)
{
int A,B;
if(p != NULL)
{
//如果当前结点的左子树和右子树非空,则为表达式,用后序遍历求值
if(p->lchild != NULL && p->rchild != NULL)
{
A = comp(p->lchild); //后序遍历求出左子树的值,赋值给A
B = comp(p->rchild); //后序遍历求出右子树的值,赋值给B
return op(A,B,p->data); //根据已求得的A与B和当前结点的运算符求出整个表达式的值
}
else
return p->data-'0'; //如果当前结点的左右子树都为空,则为数值,直接返回p->data-'0'是将字符型数字转化为整型数字
}
else
return 0; //如果是空树,则表达式的值为0
}
//函数int op(int A,int B,char C)返回的是以C为运算符,以A,B为操作数的算式的值
4.
int getDepth(BTNode *p)
{
int LD,RD;
if(p == NULL)
return 0; //如果是空树则返回0,定义空树的深度为0
else
{
LD = getDepth(p->lchild); //求左子树的深度
RD = getDepth(p->rchild); //求右子树的深度
return (LD>RD? LD:RD)+1; //返回左右子树深度的最大值+1
}
}
5.
//假设二叉树已经存在并且p指向其根节点
void search(BTNode *p,BTNode *&q,int key)
{
if(p != NULL) //如果树为空树,则什么都不做,q保持NULL值
{
if(p->data == key)
q = p;
else
{
search(p->lchild,q,key);
search(p->rchild,q,key);
}
}
}
//剪枝操作
void search(BTNode *p,BTNode *&q,int key)
{
if(p != NULL)
{
if(p->data == key)
q = p;
else
{
search(p->lchild,q,key);
if(q == NULL) //在左子树中没找到才到右子树中查找
search(p->rchild,q,key);
}
}
}
6.
int n = 0; //定义全局变量n,将结点计数初值设为0
void trave(BTNode *p,int k)
{ //前序
if(p != NULL)
{
++n; //当第一次来到一个结点的时候进行计数,表示这是第n个结点
if(k == n) //当当第一次来到一个结点的时候进行判断,看这个结点是不是先序序列中的第k个结点
{
cout<<p->data<<endl; //如果是,则输出
return; //并且无需继续遍历,用return直接返回
}
trave(p->lchild,k);
trave(p->rchild,k);
}
}
void trave(BTNode *p,int k)
{ //中序
if(p != NULL)
{
trave(p->lchild,k);
++n;
if(k == n)
{
cout<<p->data<<endl;
return;
}
trave(p->rchild,k);
}
}
void trave(BTNode *p,int k)
{//后序
if(p != NULL)
{
trave(p->lchild,k);
trave(p->rchild,k);
++n;
if(k == n)
{
cout<<p->data<<endl;
return;
}
}
}
7.层次遍历(需要一个循环队列)
void level(BTNode *p)
{
int front,rear;
BTNode *que[maxSize]; //定义一个循环队列,用来记录将要访问的层次上的结点
front = rear = 0;
BTNode *q;
if(p != NULL)
{
rear = (rear+1)%maxSize;
que[rear] = p; //根节点入队
while(front != rear) //当循环队列不空的时候进行循环
{
front = (front+1)%maxSize;
q = que[front]; //队头结点出队
Visit(q); //访问队头结点
if(q->lchild != NULL) //如果左子树不空,则左子树的根结点入队
{
rear = (rear+1)%maxSize;
que[rear] = q->lchild;
}
if(q->rchild != NULL) //如果右子树不空,则右子树的根结点入队
{
rear = (rear+1)%maxSize;
que[rear] = q->rchild;
}
}
}
}
8.
//下面所定义的这个结构类型为顺序非循环队列的队列元素,可以存储结点指针以及结点所在的层次号
typedef struct
{
BTNode *p; //结点指针
int lno;
}St;
int maxNode(BTNode *b)
{
St que[maxSize];
int front,rear; //定义顺序非循环队列
int Lno,i,j,n,max;
front = rear = 0;
BTNode *q;
if(b != NULL)
{
++rear;
que[rear].p = b; //树根入队
que[rear].lno = 0; //树根所咋层次号设置为1,此为已知条件
while(front != rear)
{
++front;
q = que[front].p;
Lno = que[front].lno; //关键语句:Lno用来存取当前结点的层次号
if(q->lchild != NULL)
{
++rear;
que[rear].p = q->lchild;
que[rear].lno = Lno + 1;
}
if(q->rchild != NULL)
{
++rear;
que[rear].p = q->rchild;
que[rear].lno = Lno + 1;
}
}//注意:循环结束后Lno保存的是这颗二叉树的最大层数
max = 0;
for(i=1;i<=Lno;++i)
{
n = 0;
for(j=1;j<=rear;++j) //rear指向队尾元素,并且队列数组中que[1]为树的根节点
if(que[j].lno == i)
++n;
if(max<n)
max = n;
}
return max;
}
else return 0; //空树直接返回0
}
三.线索二叉树
1.线索二叉树结点定义
typedef struct TBTNode
{
char data;
int ltag,rtag; //线索标记
struct TBTNode *lchild;
struct TBTNode *rchild;
}TBTNode;
2.中序线索二叉树
void InThread(TBTNode *p,TBTNode *&pre)
{
if(p != NULL)
{
InThread(p->lchild,pre); //递归,左子树线索化
if(p->lchild == NULL)
{ //建立当前结点的前驱线索
p->lchild = pre;
p->ltag = 1;
}
if(pre != NULL && pre->rchild == NULL)
{ //建立前驱结点的后继结点
pre->rchild = p;
pre->rtag = 1;
}
pre = p; //pre指向当前的p,作为p将要指向的下一个结点的前驱结点
InThread(p->rchild,pre); //递归,右子树线索化
}
}
void createInThread(TBTNode *root)
{
TBTNode *pre = NULL;
if(root != NULL)
{
InThread(root,pre);
pre->rchild = NULL; //非空二叉树,线索化后处理中序最后一个结点
pre->rtag = 1;
}
}
2.遍历中序线索二叉树
TBTNode *First(TBTNode *p)
{
while(p->ltag == 0)
p=p->lchild; //最左下结点(不一定是叶子结点)
return p;
}
TBTNode *Last(TBTNode *p)
{
while(p->rtag == 0)
p=p->rchild; //最右下结点
return p;
}
TBTNode *Next(TBTNpde *p)
{
if(p->rtag == 0)
return First(p->rchild);
else
return p->rchild;
}
TBTNode *Prior(TBTNode *p)
{
if(p->lchild == 0)
return Last(p->lchild);
else
return p->lchild;
}
void InOrder(TBTNode *root)
{
for(TBTNode *p=First(root);p!=NULL;p=Next(p))
Visit(p);
}
4.前序线索二叉树
void preThread(TBTNode *p,TBTNode *&pre)
{
if(p != NULL)
{
if(p->lchild == NULL)
{
p->lchild = pre;
p->ltag = 1;
}
if(pre != NULL && pre->rchild == NULL)
{
pre->rchild = p;
pre->rtag = 1;
}
pre = p;
//注意:这里在递归入口处有限制条件,左右指针不是线索才能继续递归
if(p->ltag == 0)
preThread(p->lchild,pre);
if(p->rtag == 0)
preThread(p->rchild,pre);
}
}
5.前序线索二叉树的遍历
void preOrder(TBTNode *root)
{
if(root != NULL)
{
TBTNode *p = root;
while(p != NULL)
{
while(p->ltag == 0) //左指针不是线索,则边访问边左移
{
Visit(p);
p = p->lchild;
}
Visit(p); //此时p左指针必为线索,但还没有访问,则访问
p = p->rchild; //此时p左孩子不存在,则右指针若非空,
//则不论是否为线索都指向其后继
}
}
}
6.后序线索二叉树
void postThread(TBTNode *p,TBTNode *&pre)
{
if(p != NULL)
{
postThread(p->lchild,pre); //递归,左子树线索化
postThread(p->rchild,pre); //递归,右子树线索化
if(p->lchild == NULL)
{
p->lchild = pre;
p->ltag = 1;
}
if(pre != NULL && pre->rchild == NULL)
{
pre->rchild = p;
pre->rtag = 1;
}
pre = p;
}
}
四.二叉排序树
1.二叉排序树的存储结构
typedef struct BTNode
{
int key; //这里将data改为key,代表关键字
struct BTNode *lchild;
struct BTNode *rchild;
}BTNode;
2.二叉排序树查找关键字算法