二叉树 存储结构

顺序存储:

#include <stdio.h>
#include <math.h>    //其中floor()函数为向下(左)取整,ceil()函数为向上(右)取整
#define MaxSize 10

typedef int ElemType;
//定义树结点
typedef struct{
    ElemType data;
    bool isEmpty;
}TreeNode;
//初始化所有结点
void InitTree(TreeNode T[]){
    for(int i=0;i<MaxSize;i++){
        T[i].isEmpty=true;
    }
}
//存入一些数据
bool InputData(TreeNode T[]){
    int j=3;
    for(int i=1;i<MaxSize;i++){
        T[i].data=j;
        T[i].isEmpty=false;
        j+=2;
    }
    return true;
}
//查找左孩子
bool Outlchild(TreeNode T[],int i,ElemType &e){
    if(i>=MaxSize)
        return false;
    if(2*i>=MaxSize||T[2*i].isEmpty==true)
        return false;
    else{
        e=T[2*i].data;
    }
    return true;   
}
/查找右孩子
bool Outrchild(TreeNode T[],int i,ElemType &e){
    if(i>=MaxSize)
        return false;
    if(2*i+1>=MaxSize||T[2*i+1].isEmpty==true)
        return false;
    else{
        e=T[2*i+1].data;
    }
    return true;   
}
//查找父节点
bool OutFather(TreeNode T[],int i,ElemType &e){
    if(i>=MaxSize)
        return false;
    if(i/2>=MaxSize||T[i/2].isEmpty==true)
        return false;
    else{
        e=T[i/2].data;
    }
    return true;   
}

//判断i所在的层次
int TreeNodefloor(TreeNode T[],int i){
    int m=2,n;
    double a=floor(log(i)/log(m))+1;//自定义的:以m为底的log(i)
    if(i>=MaxSize)
        return -1;
    else
        return a;
}
//判断i是否为叶子结点
bool isLeaf(TreeNode T[],int i){
    if(i>(MaxSize-1)/2)
        return true;
    else
        return false;
}
/main函数测试
int main(){
    TreeNode T[MaxSize];
    InitTree(T);
    InputData(T);
    int i=3;
    ElemType e;

    //查找左孩子
    if(Outlchild(T,i,e))
        printf("左孩子查找成功\n");
    else
        printf("左孩子查找失败\n");
    printf("%d\n",e);

    //查找右孩子
    if(Outrchild(T,i,e))
        printf("右孩子查找成功\n");
    else
        printf("右孩子查找失败\n");
    printf("%d\n",e);

    //查找父节点
    if(OutFather(T,i,e))
        printf("父节点查找成功\n");
    else
        printf("父节点查找失败\n");
    printf("%d\n",e);

    //判断i所在的层次
    int floor=TreeNodefloor(T,i);
    printf("a=%d\n",floor);

    //判断是否为叶子结点
    if(isLeaf(T,i))
        printf("叶子结点\n");
    else
        printf("分支结点\n");
}

二叉树的顺序存储中,一定要把二叉树的结点编号与完全二叉树对应起来

i的左孩子  2i

i的右孩子  2i+1

i的父节点[ i/2]

链式存储:

typedef struct BiTNode{
    ElemType data;//数据域
    struct BiTNode *lchild, *rchild;//左右孩子指针
}BiTNode,*BiTree;

n个结点的二叉链表共有n+1个空链域

二叉链表的创建:

    #include <stdio.h>
    #include <stdlib.h>
    #define TElemType int
    typedef struct BiTNode{
        TElemType data;//数据域
        struct BiTNode *lchild,*rchild;//左右孩子指针
    }BiTNode,*BiTree;
    void CreateBiTree(BiTree *T){
        *T=(BiTNode*)malloc(sizeof(BiTNode));
        (*T)->data=1;
        (*T)->lchild=(BiTNode*)malloc(sizeof(BiTNode));
        (*T)->rchild=NULL;
        (*T)->lchild->data=2;            
        (*T)->lchild->lchild=(BiTNode*)malloc(sizeof(BiTNode));
        (*T)->lchild->rchild=NULL;
        (*T)->lchild->lchild->data=3;
        (*T)->lchild->lchild->lchild=NULL;
        (*T)->lchild->lchild->rchild=NULL;
    }
    int main() {
        BiTree Tree;
        CreateBiTree(&Tree);
        printf("%d",Tree->lchild->lchild->data);
        return 0;
    }

二叉树的前中后序遍历:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
 
#define MAXSIZE 100
 
/**二叉树数据结构定义**/
typedef struct BiTreeNode
{
    char data;
    struct BiTreeNode *left;
    struct BiTreeNode *right;
}BiTreeNode,*BiTree;
/**二叉树的建立--按照先序方式建立--插入**/
void CreateBiTree(BiTree *T)
{
    char val;
    scanf("%c",&val);
 
    if(val == '#')
        *T = NULL;  //null表示为空枝
 
    else
    {
        *T = (BiTree)malloc(sizeof(BiTreeNode));
        (*T)->data = val;
        CreateBiTree(&(*T)->left);
        CreateBiTree(&(*T)->right);
    }
}
 /**先序遍历  根左右**/
void PreOrderTravel(BiTree T)
{
    if(T==NULL)
        return;
    printf("%c ",T->data);
    PreOrderTravel(T->left);
    PreOrderTravel(T->right);
}
 /**中序遍历 左根右**/
void InOrderTravel(BiTree T)
{
    if(T==NULL)
        return;
    InOrderTravel(T->left);
    printf("%c ",T->data);
    InOrderTravel(T->right);
}
 /**后序遍历 左右根**/
void TailOrderTravel(BiTree T)
{
    if(T==NULL)
        return;
    TailOrderTravel(T->left);
    TailOrderTravel(T->right);
    printf("%c ",T->data);
}
int main()
{
 
    printf("测试代码\n");
    BiTree T;
    T = (BiTree)malloc(sizeof(BiTreeNode));
 
    printf("请给二叉树按照先序方式依次输入结点的值(空结点为#):\n");
    CreateBiTree(&T);
 
 
    printf("先序方式遍历结果:\n");
    PreOrderTravel(T);
    printf("\n");
 
    printf("中序方式遍历结果:\n");
    InOrderTravel(T);
    printf("\n");
 
    printf("后序方式遍历结果:\n");
    TailOrderTravel(T);
    printf("\n");
    return 0;
}
int treeDepth(BiTree T){//树的深度计算
    if(T=NULL){
        return 0;
    }
    else{
        int l =treeDepth(T->lchild);
        int r =treeDepth(T->rchild);
        return l>r ?l+1:r+1;//树的深度等于Max(左子树深度,右子树深度)+1

    }


}

线索二叉树:

思路:从根节点出发,重新进行一次中序遍历,指针q记录当前访问的结点,指针pre记录上一个被访问的结点。

1当q=p时,pre为前驱

2当pre==p,q为后继

typedef struct ThreadNode {
    ElemType data;
    struct ThreadNode *lchild,*rchild;
    int ltag,rtag;
}ThreadNode,*ThreadTree;//tag==0表示指针指向孩子,tag==1,表示指针是线索


线索二叉树

ThreadNode *pre =NULL;//全局变量pre,指向当前访问节点的前驱
typedef  struct ThreadNode{
	ElemType data;
	struct ThreadNode *lchild,*rchild;
	int ltag,rtag;//tag =1的时候,表明建立线索,tag=0表明存在孩子
}ThreadNode,*ThreadTree;

void CreateInThread(ThreadTree T){
	pre =NULL;
	if(T!=NULL){
		InThread(T);
		if(pre->rchild==NULL){
			pre->rtag=1;
		}
	
	}


}

void InThread(ThreadTree T){//中序遍历二叉树,一边遍历一边线索
	if(T!=NULL){
		InThread(T->lchild);
		visit(T);
		InThread(T->rchild);	
	}
}


void visit(ThreadNode *q){
	if(q->lchild==NULL){//
		q->lchild=pre;
		q->ltag=1;
	}
	if(pre!=NULL&&pre->rchild==NULL){
		pre->rchild=q;//建立前驱结点的后继线索
		pre->rtag=1;
	}
	pre=q;
}

前序遍历(考虑转圈问题)
ThreadNode *pre =NULL;//全局变量pre,指向当前访问节点的前驱
typedef  struct ThreadNode{
	ElemType data;
	struct ThreadNode *lchild,*rchild;
	int ltag,rtag;//tag =1的时候,表明建立线索,tag=0表明存在孩子
}ThreadNode,*ThreadTree;

void CreateInThread(ThreadTree T){
	pre =NULL;
	if(T!=NULL){
		InThread(T);
		if(pre->rchild==NULL){//处理最后一个节点
			pre->rtag=1;
		}
	
	}


}

void PreThread(ThreadTree T){//中序遍历二叉树,一边遍历一边线索
	if(T!=NULL){
		visit(T);
		if(T->ltag==0){//lchild 不是前驱线索
			PreThread(T->lchild);
		}
		InThread(T->rchild);	
	}
}


void visit(ThreadNode *q){
	if(q->lchild==NULL){//
		q->lchild=pre;
		q->ltag=1;
	}
	if(pre!=NULL&&pre->rchild==NULL){
		pre->rchild=q;//建立前驱结点的后继线索
		pre->rtag=1;
	}
	pre=q;
}

前序遍历(考虑转圈问题)
ThreadNode *pre =NULL;//全局变量pre,指向当前访问节点的前驱
typedef  struct ThreadNode{
	ElemType data;
	struct ThreadNode *lchild,*rchild;
	int ltag,rtag;//tag =1的时候,表明建立线索,tag=0表明存在孩子
}ThreadNode,*ThreadTree;

void CreateInThread(ThreadTree T){
	pre =NULL;
	if(T!=NULL){
		PostThread(T);
		if(pre->rchild==NULL){//处理最后一个节点
			pre->rtag=1;
		}
	
	}


}

void PostThread(ThreadTree T){//中序遍历二叉树,一边遍历一边线索
	if(T!=NULL){
		visit(T);
		if(T->ltag==0){//lchild 不是前驱线索
			PostThread(T->lchild);
		}
		PostThread(T->rchild);	
	}
}


void visit(ThreadNode *q){
	if(q->lchild==NULL){//
		q->lchild=pre;
		q->ltag=1;
	}
	if(pre!=NULL&&pre->rchild==NULL){
		pre->rchild=q;//建立前驱结点的后继线索
		pre->rtag=1;
	}
	pre=q;
}

中序线索二叉树找出中序后继
在这里需要明确的一点是,寻找中序遍历的后继,就是寻找右子树中最左边的结点
ThreadNode * Firstnode(ThreadNode *p){//找到以p为根的子树中,第一个被遍历的结点
	while(p->rtag ==0){
		p=p->lchild;
	}
	return p;
}
ThreadNode *Nextnode(Thread *p){//在中序线索二叉树中找到结点p的后继结点
	if(p->rtag==0){//未被线索化
		return Firstnode(p->rchild);
	}
	else{
		return p->child;//线索化,直接返回后继
	}

}
void Inorder(Thread *T){
	for(ThreadNode *p =Firstnode(T):p!=NULL:p=Nextnode(p)){
		visit(p);
	}
}

中序线索二叉树找出中序前驱:

找到前驱的前提,就是代表p(结点)有左子树,如果说明有左子树的话,即找到左子树的最右的结点
//找到以p为根的子树中,最后一个被中序遍历的结点
ThreadNode *Lastnode(ThreadNode *p){
	while(p->rtag ==0)

}
ThreadNode *Prenode(ThreadNode *p){//在中序二叉树中找到结点p的前驱结点
	if(p->ltag==0){
		return Lastnode(p->lchild);
	}
	else{
		return p->rchild;
	}
}
对中序线索二叉树进行逆向中序遍历
void RevInorder(ThreadNode *T){
	for(Thread *p =Lastnode(T):p!=NULL:p=Prenode(p)){
		visit(p);
	}
}

在先序线索二叉树中找到结点*p的先序后继next

1若p->rtag==1,则next=p->rchild

2p->rtag==0,说明p一定有右孩子,如果p有左孩子,则先序后继为左孩子

                                                      如果p有右孩子,则先序后继为右孩子

在先序线索二叉树中找到结点*p的先序前驱pre

1若p->ltag==1,则next=p->lchild

2p->ltag==0  先序遍历中左右子树中的结点只可能是根的后继,不可能是前驱

采用的方法是从头开始先序遍历

 

在后序线索二叉树中找后序前驱:

1若p->ltag==1,则pre=p->lchild,

2p->ltag==0(说明一定有左孩子),后序遍历(左右根)假如p有右孩子,则后续前驱为右孩子,假如p没有右孩子,则后续前驱为左孩子,

在后序线索二叉树中找后序后继:

1p->rtag==1,则next =p->rchild

2若p->rtag==0  (后序遍历中,左右子树中的结点只能是根的前驱结点,不可能是后继结点)

解决方法:

1采用土方法进行后序遍历

2三叉链表,

                                                                    总结

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值