C语言(六)

1、二叉树的非递归遍历
本题要求用非递归的方法实现对给定二叉树的 3 种遍历。

输入:输入二叉树结点构建二叉树

输出:输出 3 个函数分别按照访问顺序打印出结点的内容

include <stdio.h>
#include <stdlib.h>
typedef enum { false, true } bool;

typedef char ElementType;
typedef struct TNode *Position;
typedef Position BinTree;
struct TNode{
    ElementType Data;
    BinTree Left;
    BinTree Right;
    int flag;
};

/*------堆栈的定义-------*/
typedef Position SElementType;
typedef struct SNode *PtrToSNode;
struct SNode {
    SElementType Data;
    PtrToSNode Next;
};
typedef PtrToSNode Stack;

/* 裁判实现,细节不表 */
Stack CreateStack();
bool IsEmpty( Stack S );
bool Push( Stack S, SElementType X );
SElementType Pop( Stack S ); /* 删除并仅返回S的栈顶元素 */
SElementType Peek( Stack S );/* 仅返回S的栈顶元素 */
/*----堆栈的定义结束-----*/

BinTree CreateBinTree(); /* 裁判实现,细节不表 */
void InorderTraversal( BinTree BT );
void PreorderTraversal( BinTree BT );
void PostorderTraversal( BinTree BT );

int main()
{
    BinTree BT = CreateBinTree();
    printf("Inorder:");    InorderTraversal(BT);    printf("\n");
    printf("Preorder:");   PreorderTraversal(BT);   printf("\n");
    printf("Postorder:");  PostorderTraversal(BT);  printf("\n");
    return 0;
}

void PreorderTraversal(BinTree BT) {//前序
	Stack S=CreateStack();
	while (BT||!IsEmpty(S)) {
		while (BT) {
			if (Push(S, BT)) {
				printf(" %c", BT->Data);
				BT=BT->Left;//一直向左走,直到没有左孩子
			}
		}
		BT=Pop(S);//出栈
		BT=BT->Right;//访问右子树
	}
}

void InorderTraversal(BinTree BT) {//中序
	Stack S=CreateStack();
	while (BT||!IsEmpty(S)) {
		while (BT){
			if (Push(S, BT)) BT=BT->Left;
		} 	
		BT=Pop(S);
		printf(" %c", BT->Data);
		BT=BT->Right;
	}
}

void PostorderTraversal(BinTree BT) {//后序
	Stack S=CreateStack();
	while (BT||!IsEmpty(S)) {
		while (BT) {
			if (Push(S, BT)) BT=BT->Left;
		}
		BT=Peek(S);
		if (BT->flag!=1) {
			BT->flag=1;
			BT=BT->Right;
		}
		else {
			BT=Pop(S);
			printf(" %c",BT->Data);
			BT=NULL;
		}
	}
}

ps:第一次遇到该结点就输出——前序遍历(入栈即访问);第二次遇到该结点就输出——中序遍历(出栈时访问);第三次遇到该结点就输出——后序遍历(左、右孩子已被访问时再出栈访问)。
前序和中序遍历的非递归实现都很简单,一直将左孩子入栈直到左孩子为空时再出栈,若出栈结点有右孩子则重复入栈操作,前序和中序遍历的区别只在于前序遍历是入栈时访问结点,中序遍历是出栈时访问结点。
后序遍历的非递归实现,通过结构体内的flag区分是第二次遇到该结点还是第三次遇到该结点。第一次遇到结点是压栈Push的时候,将flag设为0;第二次遇到结点Peek的时候,将flag设为1;第三次遇到该结点就是该输出的时候了,判断flag等于0还是1来确定该结点是否该输出。

2、是否二叉搜索树
本题要求实现函数,判断给定二叉树是否二叉搜索树。

输入:输入二叉树结点构建二叉树

输出:输出判断是否搜索二叉树

#include <stdio.h>
#include <stdlib.h>

typedef enum { false, true } bool;
typedef int ElementType;
typedef struct TNode *Position;
typedef Position BinTree;
struct TNode{
    ElementType Data;
    BinTree Left;
    BinTree Right;
};

BinTree BuildTree(); /* 由裁判实现,细节不表 */
bool IsBST ( BinTree T );

int main()
{
    BinTree T;

    T = BuildTree();
    if ( IsBST(T) ) printf("Yes\n");
    else printf("No\n");

    return 0;
}

bool IsBST ( BinTree T ){
	if(!T) //如果树为空,则返回true,即为二叉搜索树
    {
        return true;
    }
    else if(!T->left&&!T->right){//只有一个根节点
		return true;
	}
	else if(T->left&&!T->right){//存在左子树,不存在右子树
		if(T->left->data<T->data)return IsBST(T->left);
    	else 
    		return false;
	}
	else if(!T->left&&T->right){//存在右子树,不存在左子树
		if(T->data<T->right)return IsBST(T->right);
    	else 
    		return false;
	}
	else if(T->left&&T->right){//存在左、右子树
		if(T->left->data<T->data &&T->right->data>T->data){				  
			if(IsBST(T->left)&&IsBST(T->right))
				return true;
			else 
    			return false;else 
    		return false;
	}

}

ps:
验证二叉搜索树思路主要有两种:一种是递归,另一种是中序遍历。本题采用的是递归的方法,较为复杂。借鉴网上思想发现可以采用中序遍历,如果中序遍历出来的序列是递增的,即为二叉搜索树。

方法二(中序遍历):

int a[30],t=0; //数组a存储中序遍历序列
void inorderTraversal(BinTree BT) //递归中序遍历
{
    if(BT)
    {
        inorderTraversal(BT->Left);
        a[t]=BT->Data;
        t++;
        inorderTraversal(BT->Right);
    }
}
bool IsBST ( BinTree T )
{
    if(!T) //如果树为空,则返回true,即为二叉搜索树
    {
        return true;
    }
    inorderTraversal(T);
    int last=a[0];
    for(int i=1;i<t;i++)  //判断中序遍历序列是否为递增
    {
        if(a[i]<=last)
        {
            return false;
        }
        last=a[i];
    }
    return true;
}

总结:今天复习了树的相关知识,学习了树的三种遍历方法的递归和非递归形式,明日计划复习图。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值