第六章-树(3)二叉树的存储结构

1、顺序存储结构

//------二叉树的顺序存储表示-----------

#define MAX_TREE_SIZE 100         //二叉树的最大结点数

typedef TElemType SqBiTree[MAX_TREE_SIZE];       // 0 号单元存储根结点

SqBiTree bt;                      //




6.6中的(a)顺序存储结构 对应 b

6.6中的(b)顺序存储结构 对应 c

(由此可见:这种顺序存储结构仅适用于完全二叉树,因为在最坏的情况下,一个深度为k且只用k个结点的单支树却需要长度为2^k-1 的一维数组)


2、链式存储结构


二叉树的结点(如图6.7(a)所示)由一个数据元素和分别指向其左、右子树的两个分支构成,则表示二叉树的链表中 的结点至少包含3个域:数据域和左、右指针域。

有时,为了便于找到结点的双亲,则可以在结点结构中增加一个指向其双亲结点的指针域,(如图6.7(c)所示)

利用这两种结构所得二叉树的存储结构分别称之为 二叉链表 和 三叉链表。



如图6.8所示:链表的头指针指向二叉树的根结点。容易证得,在含有 n 个结点的二叉链表中有 n+1个空链域。


//-----------二叉树的二叉链表存储表示--------
typedef struct BiTNode{
	TElemType data;
	struct BiTNode *lchild,*rchild;   //左右孩子指针
}BiTNode,*BiTree;

//-----------基本操作的函数原型说明---------
Status CreateBiTree(BiTree &T);
//按先序次序输入二叉树中结点的值,空格字符表示空树
//构造二叉树链表表示的二叉树T

Status PreOrderTraverse(BiTree T,Status (*Visit)(TElemType e));
//采用二叉树的存储结构,Visit 是对结点操作的应用函数
//先序遍历

Status InOrderTraverse(BiTree T,Status (*Visit)(TElemType e));
//采用二叉树的存储结构,Visit 是对结点操作的应用函数
//中遍历

Status PostOrderTraverse(BiTree T,Status (*Visit)(TElemType e));
//采用二叉树的存储结构,Visit 是对结点操作的应用函数
//后序遍历

Status LevelOrderTraverse(BiTree T,Status (*Visit)(TElemType e));
//采用二叉树的存储结构,Visit 是对结点操作的应用函数
//层次遍历


--------------------------------------------------------------------------------------------------------------------------------

代码部分:(二叉树的二叉链表存储的方法)

#include <stdio.h>  
#include <malloc.h>  
#include <stdlib.h>  
#include <string.h>  
 
//宏定义
#define OK 1  
#define ERROR 0  
#define TRUE 1
#define FALSE 0  
#define INFEASIBLE -1
#define OVERFLOW -2
#define YES 1  
#define NO 0  

#define STACK_INIT_SIZE 100     //栈存储空间初始分配量  
#define STACKINCREMENT 10         //栈存储空间分配增量 

#define MAXSIZE 40 

typedef int Status;       /* Status是函数的类型,其值是函数结果状态代码,如OK等 */  
typedef int Boolean;      /* Boolean是布尔类型,其值是TRUE或FALSE */   
typedef char AtomType;    /* 定义原子类型为字符型 */

  
typedef char TElemType;                     // 定义原子类型为字符型 

//-----------二叉树的二叉链表存储表示--------


//-----------基本操作的函数原型说明---------
//Status CreateBiTree(BiTree &T);
//按先序次序输入二叉树中结点的值,空格字符表示空树
//构造二叉树链表表示的二叉树T

//Status PreOrderTraverse(BiTree T,Status (*Visit)(TElemType e));
//采用二叉树的存储结构,Visit 是对结点操作的应用函数
//先序遍历

//Status InOrderTraverse(BiTree T,Status (*Visit)(TElemType e));
//采用二叉树的存储结构,Visit 是对结点操作的应用函数
//中遍历

//Status PostOrderTraverse(BiTree T,Status (*Visit)(TElemType e));
//采用二叉树的存储结构,Visit 是对结点操作的应用函数
//后序遍历

//Status LevelOrderTraverse(BiTree T,Status (*Visit)(TElemType e));
//采用二叉树的存储结构,Visit 是对结点操作的应用函数
//层次遍历

typedef struct BiTNode{
	TElemType data;
	struct BiTNode *lchild,*rchild;   //左右孩子指针
}BiTNode,*BiTree;

typedef BiTree SElemType;  
  
//栈的顺序结构体  
typedef struct{  
    SElemType *base;              //在栈构造之前和销毁之后,base 的值为NULL;  
    SElemType *top;               //栈顶指针  
    int stacksize;                //当前已分配的存储空间,以元素为单位  
}SqStack;

typedef BiTree QElemType;

//队列的结构体
typedef struct QNode{
	QElemType data;
	struct QNode *next; 
}QNode,*QueuePtr;
typedef struct{
	QueuePtr front;   //队头指针
	QueuePtr rear;    //队尾指针
}LinkQueue;

typedef QueuePtr SQElemType;

//1.构造一个空队列Q
Status InitQueue(LinkQueue *Q){               
	//构造一个空队列Q
	Q->front=Q->rear=(QueuePtr)malloc(sizeof(QNode));
	if(!Q->front) exit(OVERFLOW);           //存储分配失败
	Q->front->next=NULL;
	return OK;
}

//2.若队列Q为空队列,则返回TRUE,否则返回FALSE
Status QueueEmpty(LinkQueue Q){
	if(Q.front->next==NULL)   
		return TRUE;
	else 
		return FALSE;
}

//3、队列是否为空  
Status IsQueueEmpty(LinkQueue *q)  
{  
    if (q->front)  
    {  
        return false;  
    }   
    else  
    {  
        return true;  
    }  
}  

//3.插入元素e为Q的新的队尾元素 
Status EnQueue(LinkQueue *Q,SQElemType e){
	if(IsQueueEmpty(Q)){
		Q->front=e;
		Q->rear=e;
	}
	else{
		Q->rear->next=e;
		Q->rear=e;
	}
	return OK;
}

//4. 若队列不空,则删除Q的队头元素,用e返回其值,并返回OK;否则返回 ERROR
Status DeQueue(LinkQueue *q, QNode **p)  
{  
    *p = q->front;  
  
    if (q->front == q->rear) //只有1个节点  
    {  
        q->front = NULL;  
        q->rear = NULL;  
    }   
    else  
    {  
        q->front = q->front->next;  
    }  
	return OK;
}  

//1.初始化栈  
Status InitStack(SqStack &S){  
    //构造一个空栈S  
    S.base=(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));  
    if(! S.base) exit(OVERFLOW);  //存储分配失败  
    S.top=S.base;    //当栈为空时,栈底等于栈顶  
    S.stacksize=STACK_INIT_SIZE;    //栈可存储的个数  
    return OK;  
} 

//2、入栈
Status Push(SqStack &S,SElemType e)  
{       //插入元素 e 为新的栈顶元素  
    if(S.top-S.base >= STACK_INIT_SIZE)  //栈满的时候就需要追加存储空间  
    {  
        S.base=(SElemType *)realloc(S.base,(S.stacksize+STACKINCREMENT)*sizeof(SElemType));   
        if(!S.base)  exit(OVERFLOW);    //存储空间分配失败  
  
        S.top=S.base+S.stacksize;   //栈底的位置可能改变,需要重新定位栈顶元素  
        //S.top 还是之前的那个没有存储的位置     
  
        S.stacksize = S.stacksize+STACKINCREMENT;  
    }  
    *S.top=e;  
    S.top++;  
    return OK;  
}  

//3.栈顶出栈元素  
Status Pop(SqStack &S,SElemType &e){  
    //若栈不为空,则删除 S 的栈顶元素,用 e 返回其值,并返回 OK ,否则返回ERROR  
    if(S.top == S.base)  return ERROR;  
    e=*(--S.top);     //可以不加括号,但需要记住的是,需要让 top 指针减 1 ,再取出元素  
    return OK;  
}  

//4.判断栈是否为空  
Status StackEmpty( SqStack S)  
{  
    if(S.top==S.base)  
        return YES;  
    else  
        return NO;  
}

//6.求栈顶元素  
Status GetTop(SqStack S,SElemType e)  
{  
    if(S.top==S.base)  
        return FALSE;  
    else  
        e=*(S.top-1);
	return OK;
} 

//按先序次序输入二叉树中结点的值,'#'字符表示空树,构造二叉树链表表示的二叉树T
Status CreateBiTree(BiTree &T){
	char ch;
	scanf("%c", &ch);  
	if(ch=='#')
		T=NULL;
	else{
		if(!(T=(BiTree)malloc(sizeof(BiTNode))))
			exit(OVERFLOW);
		T->data=ch;     //生成根结点
		CreateBiTree(T->lchild);    //构造左子树
		CreateBiTree(T->rchild);    //构造右子树
	}
	return OK;
}

//采用二叉树的存储结构,Visit 是对结点操作的应用函数,先序遍历
Status PreOrderTraverse(BiTree T,Status (*visit)(TElemType e)){
	if(T){
		if(visit(T->data))
			if(PreOrderTraverse(T->lchild,visit))
				if(PreOrderTraverse(T->rchild,visit))
					return OK;
		return ERROR;
	}
	else
		return OK;
}

//采用二叉树的存储结构,Visit 是对结点操作的应用函数,中序遍历
Status InOrderTraverse(BiTree T, Status (*Visit)(TElemType e))  
{  
    SqStack S;  
    InitStack(S);  
    BiTree p = T;  
    while( p || !StackEmpty(S) )  
    {  
        if(p)  
        {  
            Push(S,p);  
            p = p->lchild;   //根指针进栈,遍历左子树 
        }  
        else  
        {                //根指针退栈,访问根结点,遍历右子树
            Pop(S,p);  
            if(!Visit(p->data))  
                return ERROR;  
            p = p->rchild;  
        }  
    }  
    return OK;  
}



/*
//采用二叉树的存储结构,Visit 是对结点操作的应用函数,中序遍历
Status InOrderTraverse(BiTree T,Status (*visit)(TElemType e)){
	SqStack S;
	InitStack(S);
	BiTree p=T;
	Push(S,T);     //根指针进栈
	while(!StackEmpty(S)){
		while(GetTop(S,p) && p!=NULL)                        
			Push(S,p->lchild);       //向左走到尽头            //这一句会一直重复
		Pop(S,p);     //空指针退栈
		if(!StackEmpty(S)){     //访问结点,向右一步
			Pop(S,p);
			if(!visit(p->data)){
				return ERROR;      printf("have error!"); }
			Push(S,p->rchild);
		}
	}
	return OK;
}
*/
/*
Status InOrderTraverse  (BiTree T, Status (* visit)(TElemType e))  
{  
    if (T)  
    {  
        InOrderTraverse(T->lchild, visit);  
        visit(T->data); 
        InOrderTraverse(T->rchild, visit);  
    }  
    return OK;  
} */

  
//采用二叉树的存储结构,Visit 是对结点操作的应用函数,后序遍历
Status PostOrderTraverse(BiTree T, Status (* Visit)(TElemType e))  
{  
    if (T)  
    {  
        PostOrderTraverse(T->lchild, Visit);  
        PostOrderTraverse(T->rchild, Visit);  
        Visit(T->data);  
    }  
    return OK;  
}  

//采用二叉树的存储结构,Visit 是对结点操作的应用函数,层次遍历
Status LevelOrderTraverse(BiTree T){ //由于时间关系,在此的层次存储结构还未完全设计好,可自行解决
	if(!T){
		return ERROR;
	}
	LinkQueue m_queue;
	LinkQueue *Q;
	QNode *p,*q;

	Q = &m_queue;  
    InitQueue(Q);     //队列初始化  

	p=(QueuePtr)malloc(sizeof(QNode));
	p->next=NULL;
	p->data=T;
	EnQueue(Q,p);   //根结点入队


	while(!IsQueueEmpty(Q)){     
		DeQueue(Q, &q); //当前队首节点出队
		printf("%c ",q->data->data);
		
		


		if(q->data->lchild){    //左孩子非空,则左孩子入队   //q->data->lchild	CXX0030: Error: expression cannot be evaluated
			p=(QueuePtr)malloc(sizeof(QNode));
			p->next=NULL;
			p->data=q->data->lchild;
			EnQueue(Q,p);
		}
		if(q->data->rchild){   //右孩子非空,则右孩子入队
			p=(QueuePtr)malloc(sizeof(QNode));
			p->next=NULL;
			p->data=q->data->rchild;
			EnQueue(Q,p);
		}
	}
	return OK;
}

Status visit(TElemType e){
	printf("%c",e);
	return OK;
}

void main(){
	BiTree T;
	CreateBiTree(T);
	printf("\nPre: ");
	PreOrderTraverse(T,visit);

	printf("\nIn: ");
	InOrderTraverse(T,visit);

	printf("\nPost: ");
	PostOrderTraverse(T, visit);
	printf("\n");

	printf("\nLevel: ");
	LevelOrderTraverse(T);
	printf("\n");
}

代码的运行结果:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值