数据结构学完有好长时间了。渐渐忘记了很多,在此机会以做笔记的形式将其复习一般,同时熟悉敲点代码熟悉VIM。
一,基本概念
1,二叉树是节点的有限集合,该集合或者为空(而树不允许为空)或者是由一个根和两棵互不相交的、称为该根的左子树和右子树组成。
2,几种特殊的二叉树
满二叉树:高度为h的二叉树敲好有2h -1个结点时称为满二叉树
完全二叉树:一个二叉树中,只有最下面两层结点的度(一个结点拥有的子树)小于2,并且最下一层的叶结点集中靠在左侧的若干位置上
扩充二叉树:也称2-树,扩充二叉树除叶子结点外,其余结点都必须有两个孩子。
如下图所示,显示集中特殊的二叉树。
二,二叉树的存储
1)完全二叉树可以采用顺序存储。
2)一般二叉树采用链式存储
lchild | data | rchild |
三,二叉树的遍历
统称分为深度遍历和广度遍历,深度遍历即:先序、中序、后续。而广度即按层次遍历
先序:若二叉树为空,则空操作,否则先访问根节点,再遍历先序左子树,最后先序右子树
中序:若二叉树为空,则空操作,否则先中序遍历左子树,再先访问根节点,最后中序遍历右子树
后序:若二叉树为空,则空操作,否则先后序遍历左子树,再后序遍历右子树,最后访问根结点
四、程序的具体实现
/*
* =====================================================================================
*
* Filename: bttree.c
*
* Description: 实现二叉树的各种遍历
*
* Version: 1.0
* Created: 2012年08月08日 00时38分11秒
* Revision: none
* Compiler: gcc
*
* =====================================================================================
*/
#include <stdlib.h>
#include <stdio.h>
/*二叉树节点的定义*/
typedef struct BiTNode{
int data;
struct BiTNode *lchild,*rchild;
}BiTNode;
/*处理后序遍历的数据结构 */
typedef struct Pstack{
BiTNode *p;
int flag;
}Pstack;
/*队列结构*/
typedef struct Queue{
BiTNode * arry[20];
int front;
int tail;
}Queue;
static BiTNode *stack[20];
static Pstack pstack[20];
/* 处理函数,完成打印工作 */
void visit(int e)
{
printf("%d ",e);
return ;
}
/* 创建二叉树 */
BiTNode * CreateBiTree()
{
int ch;
BiTNode *T;
scanf("%d",&ch);
if (ch==0)
T=NULL;
else
{
if(!(T=(BiTNode*)malloc(sizeof(BiTNode))))
exit(1);
T->data=ch;
printf("请输入节点%d的左孩子\n",ch);
T->lchild=CreateBiTree();/*构造左子树*/
printf("请输入节点%d的右孩子\n",ch);
T->rchild=CreateBiTree();/*构造右子树*/
}
return T;
}
/* 前序遍历的递归算法 */
void PreOrder(BiTNode *T,void(*visit)(int e))
{
if (T==NULL)
{
return ;
}
else
{
visit(T->data);
PreOrder(T->lchild,visit);/*遍历左子树*/
PreOrder(T->rchild,visit);/*遍历右子树*/
}
}
/* 前序遍历的非递归算法 */
int PreOrderTraverse(BiTNode *T, void (*visit)(int e))
{
BiTNode *temp;
int i=0;
stack[i]=T;
while(i!=-1)
{
while(stack[i])/*完成打印根节点现将右孩子入栈,再将左孩子入栈*/
{
temp=stack[i];
visit(temp->data);
stack[i]=temp->rchild;
stack[++i]=temp->lchild;
}
while((stack[i])==NULL&&(i!=-1)) i--;/*空指针退栈 */
}
return 1;
}
/*中序遍历递归算法*/
int InOrder(BiTNode *T,void (*visit)(int e))
{
if (T==NULL)
return;
else
{
InOrder(T->lchild,visit);/*遍历左子树 */
visit(T->data);/* 输出根节点 */
InOrder(T->rchild,visit);/* 遍历右子树 */
}
}
/* 中序遍历非递归算法 */
int InOrderTraverse(BiTNode *T ,void (*visit)(int e))
{
BiTNode *temp;
int i=0;
stack[i]=T;
while(i!=-1)
{
while(stack[i])/*找到最左下的节点 */
{
stack[++i]=stack[i-1]->lchild;
}
i--;/*空指针退栈 */
if(i!=-1)
{
visit(stack[i]->data);/*打印关键 */
temp=stack[i--];/*栈顶元素退栈退栈*/
stack[++i]=temp->rchild;/*将栈顶元素的右孩子压入堆栈*/
}
}
return 1;
}
/* 后续遍历递归算法 */
int PostOrder(BiTNode *T,void (*visit)(int e))
{
if(T==NULL)
return;
else
{
PostOrder(T->lchild,visit);
PostOrder(T->rchild,visit);
visit(T->data);
}
}
/*后续遍历非递归算法 */
int PostOrderTraverse(BiTNode *T,void (*visit)(int e))
{
BiTNode *temp;
int i=0;
pstack[i].p=T;
while(i!=-1)
{
while(pstack[i].p&&(pstack[i].flag!=1))/*先将右孩子压栈,再将左孩子入栈*/
{
temp=pstack[i].p;
pstack[i].flag=1;
pstack[++i].p=temp->rchild;
pstack[i].flag=2;
pstack[++i].p=temp->lchild;
}
while((pstack[i].p)==NULL&&(i!=-1)) i--;/*空指针退栈 */
temp=pstack[i].p;
if(pstack[i].flag==1/*表示左右孩子都已经处理 */)
{
visit(temp->data);
i--;
}
}
return 1;
}
/*按层编历二叉树 */
int LevelOrderTraverse(BiTNode *T,void (*visit)(int e))
{
Queue queue;
queue.tail=queue.front=0;
BiTNode *temp;
queue.arry[queue.tail++]=T;
while(queue.front != queue.tail)
{
temp=queue.arry[queue.front++];
if(temp!=NULL)
{
visit(temp->data);
queue.arry[queue.tail++]=temp->lchild;
queue.arry[queue.tail++]=temp->rchild;
}
}
}
int main()
{
BiTNode *bitree;
bitree=CreateBiTree();
printf("前序遍历\n");
printf("递归 :");
PreOrder(bitree,visit);
printf("\n非递归:");
PreOrderTraverse(bitree,visit);
printf("\n中序遍历\n");
printf("递归 :");
InOrder(bitree,visit);
printf("\n非递归:");
InOrderTraverse(bitree,visit);
printf("\n后序遍历\n");
printf("递归 :");
PostOrder(bitree,visit);
printf("\n非递归:");
PostOrderTraverse(bitree,visit);
printf("\n");
printf("按层次遍历\n");
LevelOrderTraverse(bitree,visit);
printf("\n");
return 0;
}
测试结果如下: