浙江大学数据结构-陈越 编程题3

3.1 树与树的表示

树的定义

树(Tree):n(n ≥ \geq 0)个结点构成的有限集合。
当 n=0 时,称为 空树 ;对于任一棵 非空树(n>0),它具备以下性质:

  • 树中有一个称为 “根(Root)” 的特殊结点,用 r 表示;
  • 其余结点可分为 m(m>0) 个 互不相交 的有限集 T 1 T_1 T1 T 2 T_2 T2,…, T m T_m Tm,其中每个集合本身又是一棵,称为原来树的“子树(SubTree)”;
  • 子树是 不相交 的;
  • 除了根节点外,每个结点有且只有一个父结点
  • 一颗N个结点的树有 N-1条边

树的一些基本术语

术语意义
结点的度(Degree)结点的子树个树
树的度树的所有结点中最大的度数
叶结点(Leaf)度为0的结点
父结点(Parent)有子树的结点是其子树的根结点的父结点
子结点(Child)若A结点是B结点的父结点,则称B结点是A结点的子结点
兄弟结点(Sibling)具有同一父结点的各结点彼此是兄弟结点
路径和路径长度从结点 n 1 n_1 n1 n k n_k nk路径为一个结点序列,路径所包含边的个数为路径的长度
祖先结点(Ancestor)沿树根到某一结点路径上的所有结点都是这个结点的祖先结点
子孙结点(Descendant)某一结点的子树中的所有结点是这个结点的子孙
结点的层次(Level)规定根节点在1层,其他任一结点的层数是其父结点的层数加1
树的深度(Depth)树中所有结点中的最大层次是这棵树的深度

3.2 二叉树及存储结构

二叉树的定义

二叉树T:一个有穷的结点集合。这个集合可以为空;若不为空,则其是由根节点和称为其 左子树 T L T_L TL右子树 T R T_R TR 的两个不相交的二叉树组成。

  • 二叉树具有五种基本形态;
  • 二叉树的子树有左右顺序之分
  • 完全二叉树(Complete Binary Tree):有n个结点的二叉树,对树中结点按从上至下、从左到右顺序进行编号,编号为i(1 ≤ \leq i ≤ \leq n)结点与满二叉树中编号为 i 结点在二叉树中位置相同。

二叉树的性质

  • 一个二叉树第 i 层的最大结点数为: 2 i − 1 2^{i-1} 2i1 i ≥ 1 i\geq1 i1
  • 深度为 k 的二叉树有最大结点总数为: 2 k − 1 2^{k}-1 2k1 k ≥ 1 k\geq1 k1
  • 对任何非空二叉树 T,若 n 0 n_0 n0表示叶结点的个数, n 2 n_2 n2是度为2的非叶结点个数,那么两者满足关系 n 0 = n 2 + 1 n_0=n_2+1 n0=n2+1

二叉树的存储结构

顺序存储结构

对于按从上至下、从左到右顺序存储的完全二叉树,可用数组进行顺序存储。n个结点的完全二叉树的结点父子关系:

  • 非根节点的父结点的序号是 i/2;
  • 结点(序号为 i)的左孩子结点的序号是 2i,若 2i ≤ \leq n则没有左孩子;
  • 结点(序号为 i)的右孩子结点的序号是 2i+1,若 2i+1 ≤ \leq n则没有右孩子。
    对于一般二叉树也可用数组进行顺序存储,但会造成空间浪费。

链表存储结构

typedef struct TNode *Position;
typedef Position BinTree; /* 二叉树类型 */
struct TNode{ /* 树结点定义 */
    ElementType Data; /* 结点数据 */
    BinTree Left;     /* 指向左子树 */
    BinTree Right;    /* 指向右子树 */
};

3.3 二叉树的遍历

先中后递归遍历

先序遍历:

  1. 访问根节点
  2. 先序遍历其左子树
  3. 先序遍历其右子树
void PreorderTraversal( BinTree BT ){
    if( BT ) {
        printf("%d ", BT->Data );
        PreorderTraversal( BT->Left );
        PreorderTraversal( BT->Right );
    }
}

中序遍历:

  1. 中序遍历其左子树
  2. 访问根节点
  3. 中序遍历其右子树
void InorderTraversal( BinTree BT ){
    if( BT ) {
        InorderTraversal( BT->Left );
        /* 此处假设对BT结点的访问就是打印数据 */
        printf("%d ", BT->Data); /* 假设数据为整型 */
        InorderTraversal( BT->Right );
    }
}

后序遍历:

  1. 后序遍历其左子树
  2. 后序遍历其右子树
  3. 访问根节点
void PostorderTraversal( BinTree BT ){
    if( BT ) {
        PostorderTraversal( BT->Left );
        PostorderTraversal( BT->Right );
        printf("%d ", BT->Data);
    }
}

先序、中序和后序遍历过程:遍历过程中经过结点的路线一样,只是访问各结点的时机不同

中序非递归遍历

  1. 遇到一个结点,就将其压栈,并去遍历它的左子树;
  2. 当左子树遍历结束后,从栈顶弹出这个结点并访问;
  3. 然后按其右指针再去中序遍历该结点的右子树。
void InOrderTraversal( BinTree BT ){
	BinTree T = BT;
	Stack S = CreatStack( MaxSize ); /*创建并初始化栈S*/
	while( T || !IsEmpty(S) ){
		while(T){ /*一直向左并将沿途结点压入堆栈*/
			Push(S, T);
			T = T->Left;
		}
		if(!IsEmpty(S)){
			T = Pop(S); /*结点弹出堆栈*/
			printf("%5d", T->Data); /*(访问)打印结点*/
			T = T->Right;
		}
	}
}

层序遍历

队列实现:遍历从根结点开始,首先将根结点入队,然后开始执行循环:结点出队、访问该结点、其左右儿子入队。

void LevelorderTraversal ( BinTree BT ){ 
    Queue Q; 
    BinTree T;
    if ( !BT ) return; /* 若是空树则直接返回 */
    Q = CreatQueue(); /* 创建空队列Q */
    AddQ( Q, BT );
    while ( !IsEmpty(Q) ) {
        T = DeleteQ( Q );
        printf("%d ", T->Data); /* 访问取出队列的结点 */
        if ( T->Left )   AddQ( Q, T->Left );
        if ( T->Right )  AddQ( Q, T->Right );
    }
}

题目

  1. 树的同构 小白专场会做详细讲解,基本要求,一定要做;
  2. List Leaves 训练建树和遍历基本功,一定要做;
  3. Tree Traversals Again 是2014年秋季PAT甲级考试真题,稍微要动下脑筋,想通了其实程序很基础,建议尝试。

第一题

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

#define MaxTree 10
#define ElementType char
#define Tree int
#define Null -1
struct TreeNode{
    ElementType Element;
    Tree Left;
    Tree Right;
} T1[MaxTree], T2[MaxTree];

int Isomorphic(Tree, Tree);
Tree BuildTree(struct TreeNode T[]);

int main(){
    Tree R1, R2;
    R1 = BuildTree(T1);
    R2 = BuildTree(T2);
    if (Isomorphic(R1, R2))
        printf("Yes");
    else
        printf("No");
    return 0;
}

int Isomorphic(Tree R1,Tree R2)
{
    if ( (R1==Null) && (R2==Null) ) /* both empty */
        return 1;
    if ( ((R1==Null) && (R2!=Null)) || ((R1!=Null) && (R2==Null)) )
        return 0; /* one of them is empty */
    if ( T1[R1].Element != T2[R2].Element )
        return 0; /* roots are different */
    if ( ( T1[R1].Left == Null )&&( T2[R2].Left == Null ) )
        // both have no left subtree
        return Isomorphic( T1[R1].Right, T2[R2].Right );
    if ( ((T1[R1].Left!=Null)&&(T2[R2].Left!=Null))&&((T1[T1[R1].Left].Element)==(T2[T2[R2].Left].Element)) )
        // no need to swap the left and the right
        return ( Isomorphic( T1[R1].Left, T2[R2].Left ) && Isomorphic( T1[R1].Right, T2[R2].Right ) );
    else /* need to swap the left and the right */
        return ( Isomorphic( T1[R1].Left, T2[R2].Right) && Isomorphic( T1[R1].Right, T2[R2].Left ) );
}

Tree BuildTree(struct TreeNode T[]){
    int N = 0;
    int Root = Null;
    char cl, cr;
    int check[10] = {0};
    scanf("%d", &N);
    if(N){
        for(int i=0; i<N; i++)
            check[i] = 0;
        for(int i=0; i<N; i++){
            scanf("\n%c %c %c", &T[i].Element,&cl,&cr);
            if(cl != '-'){
                T[i].Left = cl - '0';
                check[T[i].Left] = 1;
            }
            else
                T[i].Left=Null;
            if(cr!='-'){
                T[i].Right = cr - '0';
                check[T[i].Right] = 1;
            }
            else
                T[i].Right = Null;
        }
        for(int i=0; i<N; i++){
            if(check[i]==0){
                Root=i;
                break;
            }
        }
    }
    return Root;
}

第二题

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

#define MaxTree 10
#define MaxSize 10
#define Tree int
#define Null -1
struct TreeNode{
    Tree Left;
    Tree Right;
} T[MaxTree];

Tree BuildTree(struct TreeNode T[]);
void LeaveFind(Tree R);
int IsLeaves(Tree R);

int main(){
    Tree R;
    R = BuildTree(T);
    LeaveFind(R);
    return 0;
}

Tree BuildTree(struct TreeNode T[]){
    int N;
    Tree Root = Null;
    int check[10];
    char cl, cr;
    scanf("%d",&N);
    if(N){
        for(int i=0; i<N; i++)
            check[i]=0;
        for(int i=0; i<N; i++){
            scanf("\n%c %c", &cl, &cr);
            if(cl != '-'){
                T[i].Left = cl-'0';
                check[T[i].Left]=1;
            }
            else
                T[i].Left=Null;
            if(cr != '-'){
                T[i].Right = cr-'0';
                check[T[i].Right] = 1;
            }
            else
                T[i].Right=Null;
        }
        for(int i=0; i<N; i++){
            if(!check[i]){
                Root=i;
                break;
            }
        }
    }
    return Root;
}

LeaveFind(Tree R){
    int flag = 0;
    int Queue[MaxSize];
    int head = 0;
    int rear = 0;
    Queue[rear++] = R;//根节点放入队列
    while(rear-head){
        if(IsLeaves(Queue[head])){
            if(flag)
                printf(" ");
            printf("%d",Queue[head]);
            flag=1;
        }
        else{
            if(T[Queue[head]].Left != Null)
                Queue[rear++] = T[Queue[head]].Left;
            if(T[Queue[head]].Right != Null)
                Queue[rear++] = T[Queue[head]].Right;
        }
        head++;
    }
}

int IsLeaves(Tree R){
    if(T[R].Left==Null && T[R].Right==Null)
        return 1;
    else
        return 0;
}


第三题

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

#define MaxSize 30
#define ElementType int

typedef struct SNode *Stack;
struct SNode{
    ElementType Data;
    struct SNode *Next;
};

Stack CreateStack();
int IsEmpty(Stack S);
void Push( ElementType item, Stack S);
ElementType Pop(Stack S);
void Array_Build();
void Post_Array(int preL, int inL, int postL, int n);
void Post_Print(int N);
int pre[MaxSize], in[MaxSize], pos[MaxSize];

int main(){
    int N;
    scanf("%d", &N);
    Array_Build(N);
    Post_Array(0, 0, 0, N);
    Post_Print(N);
    return 0;
}

void Array_Build(int N){
    char str[10];
    int j = 0, k = 0;
    int x;
    Stack s = CreateStack();
    for(int i=0; i<2*N; i++){
        scanf("%s", str);
        if(strcmp(str, "Push") == 0){
            scanf("%d", &x);
            pre[j++] = x;
            Push(x, s);
        }
        else
            in[k++] = Pop(s);
    }
}

Stack CreateStack(){
    Stack S;
    S =(Stack)malloc(sizeof(struct SNode));
    S->Next = NULL;
    return S;
}

int IsEmpty(Stack S){
    return ( S->Next == NULL );
}

void Push( ElementType item, Stack S){
    Stack TmpCell;
    TmpCell = (Stack)malloc(sizeof(struct SNode));
    TmpCell->Data = item;
    TmpCell->Next = S->Next;
    S->Next = TmpCell;
}

ElementType Pop(Stack S){
    Stack FirstCell;
    ElementType TopElem;
    if( IsEmpty( S ) ) {
        printf("堆栈空");
        return NULL;
    }
    else {
        FirstCell = S->Next;
        S->Next = FirstCell->Next;
        TopElem = FirstCell ->Data;
        free(FirstCell);
        return TopElem;
    }
}

void Post_Array(int preL, int inL, int postL, int n){
    int i, root, Left, Right;
    if(n == 0)
        return;
    if(n == 1)
        pos[postL] = pre[preL];
    root = pre[preL];
    pos[postL+n-1] = root;
    for(i=0; i<n; i++)
        if(root == in[inL+i])
            break;
    Left = i;
    Right = n-1-Left;
    Post_Array(preL+1, inL, postL, Left);
    Post_Array(preL+1+Left, inL+Left+1, postL+Left, Right);
    
}

void Post_Print(int N){
    int first = 1;
	for(int i=0; i<N; i++){
		if(first){
			first = 0;
			printf("%d",pos[i]);
		}
        else
			printf(" %d",pos[i]);
	}
}

参考

浙江大学MOOC数据结构-陈越、何钦铭 编程练习题(第三讲)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值