二叉树的链式存储

顺序存储

有n个节点的完全二叉树可以用有n+1个元素的数组进行顺序存储,节点号和数组下标 一一对应。
不完全二叉树通过添加虚节点构成 完全二叉树,然后用数组存储,这要浪费一些存储空间。
在这里插入图片描述

最坏的情况下,一个深度为k且只有k个结点的单支树却需要长度为2k-1的一维数组。
总结: 顺序存储浪费空间。

链式存储

数据的描述

描述: 数据域+左右指针域

typedef char datatype;

typedef struct node {
	datatype data;
	struct node *lchild;//左孩子
	struct node *rchild;//右孩子
}btree, *btree_t;

二叉树的创建

树的结构定义是一个递归的定义,即在树的定义中又用到了树的概念。所以创建也采用递归的方式创建。

btree_t createBtree()
{
	//1.获取数据
	datatype x;
	btree_t T = NULL;

	scanf("%c", &x);

	//2.数据有效,创建根结点存放
	if('#' == x)
		return NULL;

	T = (btree_t)malloc(sizeof(btree));
	if(NULL == T)
	{
		perror("malloc");
		return NULL;
	}

	T->data = x;

	//3.还有数据,递归创建左结点存放
	T->lchild = createBtree();

	//4.还有数据,递归创建右结点存放
	T->rchild = createBtree();

	return T;
}

二叉树的遍历

由于二叉树的递归性质,遍历算法也是递归的。
三种遍历方式: 先序遍历、中序遍历、后序遍历。
在这里插入图片描述

先序遍历

void pre_order(btree_t T)//前序
{
	//空则不遍历
	if(NULL == T)
	{
		return ;
	}

	//非空才遍历
	printf("%c", T->data);//根
	pre_order(T->lchild);//左子树
	pre_order(T->rchild);//右子树

}

在这里插入图片描述

中序遍历

void in_order(btree_t T)//中序
{
	//空则不遍历
	if(NULL == T)
	{
		return ;
	}

	//非空才遍历
	in_order(T->lchild);//左子树
	printf("%c", T->data);//根
	in_order(T->rchild);//右子树

	return ;
	
}

后序遍历

void post_order(btree_t T)//后序
{
	//空则不遍历
	if(NULL == T)
	{
		return ;
	}

	//非空才遍历
	post_order(T->lchild);//左子树
	post_order(T->rchild);//右子树
	printf("%c", T->data);//根

	return ;

}

层序遍历

在这里插入图片描述
该图来自mooc浙江大学数据结构课程

void Levelorder ( btree_t T )
{
	if ( !T ) return; /* 若是空树则直接返回 */
	
    btree_t Temp;
    sequeue *Q = createSeQueue(); /* 创建空队列Q */
    
    inSeQueue( Q, T );
    while ( !isEmptySeQueue(Q) ) 
	{
        OutSeQueue( Q, &Temp );
        printf("%c ", Temp->data); /* 访问取出队列的结点 */
        if ( Temp->lchild )   
			inSeQueue( Q, Temp->lchild );
        if ( Temp->rchild )  
			inSeQueue( Q, Temp->rchild );
    }
}

测试

在这里插入图片描述
在这里插入图片描述

	btree_t T = createBtree();
	if(NULL == T)
	{
		printf("创建二叉树失败");
		return -1;
	}

	printf("pre: ");
	pre_order(T);
	printf("\n");

	printf("in: ");
	in_order(T);
	printf("\n");

	printf("post: ");
	post_order(T);
	printf("\n");

    return 0;

先序 中序 后序的非递归遍历算法

利用堆栈
在这里插入图片描述
沿着如图所示路径遍历。
先序遍历就是在第一次遇到结点的时候输出,中序在第二次遇到的时候输出,后序是在第三次遇到的时候输出。

void preOder(btree_t T)
{
	seqstack * s = (seqstack *)malloc(sizeof(seqstack));//创建空栈
	
	while(T || !isEmpty(s)) 
	{
		while(T)
		{
			push(s, T);	//第一次碰到,将该结点指针入栈,并输出其数据
			printf("%c", T->data);
			T = T->lchild;//T指向T的左孩子 
		}
		
		if(!isEmpty(s))	//出栈,直到栈为空 
		{
			T = pop(s);	//第二次碰到,出栈该结点 
			
			T = T->rchild;			
		}
	}
}

void inOder(btree_t T)
{
	seqstack * s = (seqstack *)malloc(sizeof(seqstack));//创建空栈
	
	while(T || !isEmpty(s)) 
	{
		while(T)
		{
			push(s, T);	//第一次碰到,将该结点指针入栈
			T = T->lchild;//T指向T的左孩子 
		}
		
		if(!isEmpty(s))	//出栈,直到栈为空 
		{
			T = pop(s);	//第二次碰到,出栈该结点,并输出其数据 
			printf("%c", T->data);
			T = T->rchild;			
		}
	}
}

后序

void PostOrderTraversal(Bintree BT)
{
    Bintree T=BT;
    Bintree flag=NULL;//flag记录结点是否已被访问过
    Bintree top;
    Stack S=CreateStack(MaxSize);
    while(T || !IsEmpty(S))
    {
        while(T)
        {
            push(S,T);
            T=T->Left;
        }             //一路向左,将沿途结点压栈
        top=GetTop(S);        //获取栈顶元素,此时不出栈
        if(top->Right==NULL || top->Right==flag)  //此时top的左子树在上一个while循环中已访问过。当top的右子树为空或已访问过时打印top结点
        {
            printf("%5d",top->Data);
            flag=pop(s);    //用flag记录这个元素,表示已访问
        }
        else
            T=top->Right;       //若top的右子树没有被访问过,则将其当做一颗新二叉树访问
    }
}

网上看到一个很有意思的程序,也分享一下:

void PostOrderTraversal( BinTree BT )
 {   
     BinTree T =BT;   
     Stack S = CreatStack( MaxSize ); 
     Stack Q = CreatStack( MaxSize );
     while( T || !IsEmpty(S) )
    {  
       while(T)
       { 
         Push(S,T);  
           Push(Q,T);
         T = T->Right;
        }          //向右将沿途结点一路压栈
       if(!IsEmpty(S))
       {  
         T = Pop(S);
         T = T->Left; //转向左子树
        }   
   }  
   while( !IsEmpty(Q) )
    { 
      T = Pop(Q);
      printf(%5d”, T->Data); 
    }  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值