2024 数据结构(浙大慕课)PAT题 —— 第一部分

二叉树部分及以前的习题

函数题

01-复杂度3 二分查找(分数20)

题目要求
本题要求实现二分查找算法

函数接口定义:

Position BinarySearch( List L, ElementType X );

List结构定义如下:

typedef int Position;
typedef struct LNode *List;
struct LNode {
    ElementType Data[MAXSIZE];
    Position Last; /* 保存线性表中最后一个元素的位置 */
};

L是用户传入的一个线性表,其中 ElementType 元素可以通过>、==、<进行比较,并且题目保证传入的数据是递增有序的。函数 BinarySearch 要查找 X 在 Data 中的位置,即数组下标(注意:元素从下标1开始存储)。找到则返回下标,否则返回一个特殊的失败标记NotFound。

裁判测试程序样例:

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

#define MAXSIZE 10
#define NotFound 0
typedef int ElementType;

typedef int Position;
typedef struct LNode *List;
struct LNode {
    ElementType Data[MAXSIZE];
    Position Last; /* 保存线性表中最后一个元素的位置 */
};

List ReadInput(); /* 裁判实现,细节不表。元素从下标1开始存储 */
Position BinarySearch( List L, ElementType X );

int main()
{
    List L;
    ElementType X;
    Position P;

    L = ReadInput();
    scanf("%d", &X);
    P = BinarySearch( L, X );
    printf("%d\n", P);

    return 0;
}

/* 你的代码将被嵌在这里 */

输入样例1:

5
12 31 55 89 101
31

输出样例1:

2

输入样例2:

3
26 78 233
31

输出样例2:

0

代码

Position BinarySearch( List L, ElementType X ){
    Position first = 1, end = L -> Last, middle = 1;
    while(first <= end){
        middle = ( first + end ) / 2;
        if( X == L -> Data[middle] ) return middle;
        else if( X < L -> Data[middle] ) end = middle - 1;
        else first = middle + 1;
        /*以下的代码也能跑,但可能会超时。
        //因为已经判定了X和middle不相等,才会继续进行对半寻找
        //关键是first 可以等于 end
        //如果end = middle,则又相当于跟middle比较一次。
        else if( X < L -> Data[middle] ) end = middle;
        else first = middle;*/
    }
    return NotFound;
}

02-线性结构1 两个有序链表序列的合并(分数15)

题目要求
本题要求实现一个函数,将两个链表表示的递增整数序列合并为一个非递减的整数序列。
函数接口定义:

Position BinarySearch( List L, ElementType X );

List结构定义如下:

typedef struct Node *PtrToNode;
struct Node {
    ElementType Data; /* 存储结点数据 */
    PtrToNode   Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */

L1和L2是给定的带头结点的单链表,其结点存储的数据是递增有序的;函数Merge要将L1和L2合并为一个非递减的整数序列。应直接使用原序列中的结点,返回归并后的带头结点的链表头指针。
裁判测试程序样例:

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

typedef int ElementType;
typedef struct Node *PtrToNode;
struct Node {
    ElementType Data;
    PtrToNode   Next;
};
typedef PtrToNode List;

List Read(); /* 细节在此不表 */
void Print( List L ); /* 细节在此不表;空链表将输出NULL */

List Merge( List L1, List L2 );

int main(){
    List L1, L2, L;
    L1 = Read();
    L2 = Read();
    L = Merge(L1, L2);
    Print(L);
    Print(L1);
    Print(L2);
    return 0;
}

/* 你的代码将被嵌在这里 */

输入样例

3
1 3 5
5
2 4 6 8 10

输出样例

1 2 3 4 5 6 8 10 
NULL
NULL

代码

List Merge( List L1, List L2 ){
    List t1, t2, L, LRear;
    L = (List)malloc(sizeof(struct Node));
    
    t1 = L1 -> Next;
    t2 = L2 -> Next;
    LRear = L;
    
    while(t1 != NULL && t2 != NULL){
        if(t1 -> Data < t2 -> Data){
            LRear -> Next = t1;
            LRear = t1;
            t1 = t1 -> Next;
        }
        else{
            LRear -> Next = t2;
            LRear = t2;
            t2 = t2 -> Next;
        }
    }
    //可以直接把剩下的数据的头结点直接接到上一个的末尾,因为可以直接用原来的节点。
    if(t1) LRear -> Next = t1;
    if(t2) LRear -> Next = t2;
    L1 -> Next = NULL;
    L2 -> Next = NULL;
    return L;
}

04-树7 二叉搜索树的操作集(分数30)

题目要求
本题要求实现给定二叉搜索树的5种常用操作。
函数接口定义:

BinTree Insert( BinTree BST, ElementType X );
BinTree Delete( BinTree BST, ElementType X );
Position Find( BinTree BST, ElementType X );
Position FindMin( BinTree BST );
Position FindMax( BinTree BST );

BinTree结构定义如下:

typedef struct TNode *Position;
typedef Position BinTree;
struct TNode{
    ElementType Data;
    BinTree Left;
    BinTree Right;
};
  • 函数Insert将X插入二叉搜索树BST并返回结果树的根结点指针;
  • 函数Delete将X从二叉搜索树BST中删除,并返回结果树的根结点指针;如果X不在树中,则打印一行Not Found并返回原树的根结点指针;
  • 函数Find在二叉搜索树BST中找到X,返回该结点的指针;如果找不到则返回空指针;
  • 函数FindMin返回二叉搜索树BST中最小元结点的指针;
  • 函数FindMax返回二叉搜索树BST中最大元结点的指针。
    裁判测试程序样例:
#include <stdio.h>
#include <stdlib.h>

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

void PreorderTraversal( BinTree BT ); /* 先序遍历,由裁判实现,细节不表 */
void InorderTraversal( BinTree BT );  /* 中序遍历,由裁判实现,细节不表 */

BinTree Insert( BinTree BST, ElementType X );
BinTree Delete( BinTree BST, ElementType X );
Position Find( BinTree BST, ElementType X );
Position FindMin( BinTree BST );
Position FindMax( BinTree BST );

int main(){
    BinTree BST, MinP, MaxP, Tmp;
    ElementType X;
    int N, i;

    BST = NULL;
    scanf("%d", &N);
    for ( i=0; i<N; i++ ) {
        scanf("%d", &X);
        BST = Insert(BST, X);
    }
    printf("Preorder:"); PreorderTraversal(BST); printf("\n");
    MinP = FindMin(BST);
    MaxP = FindMax(BST);
    scanf("%d", &N);
    for( i=0; i<N; i++ ) {
        scanf("%d", &X);
        Tmp = Find(BST, X);
        if (Tmp == NULL) printf("%d is not found\n", X);
        else {
            printf("%d is found\n", Tmp->Data);
            if (Tmp==MinP) printf("%d is the smallest key\n", Tmp->Data);
            if (Tmp==MaxP) printf("%d is the largest key\n", Tmp->Data);
        }
    }
    scanf("%d", &N);
    for( i=0; i<N; i++ ) {
        scanf("%d", &X);
        BST = Delete(BST, X);
    }
    printf("Inorder:"); InorderTraversal(BST); printf("\n");

    return 0;
}
/* 你的代码将被嵌在这里 */

输入样例

10
5 8 6 2 4 1 0 10 9 7
5
6 3 10 0 5
5
5 7 0 10 3

输出样例

Preorder: 5 2 1 0 4 8 6 7 10 9
6 is found
3 is not found
10 is found
10 is the largest key
0 is found
0 is the smallest key
5 is found
Not Found
Inorder: 1 2 4 6 8 9

代码

BinTree Insert( BinTree BST, ElementType X ){
    if( !BST ){
        BST = (BinTree)malloc(sizeof(struct TNode));
        BST -> Data = X;
        BST -> Left = NULL;
        BST -> Right = NULL;
    }
    else if( X < BST -> Data ) BST -> Left = Insert (BST -> Left, X);
    else if( X > BST -> Data ) BST -> Right = Insert (BST -> Right, X);
    return BST;
}

BinTree Delete( BinTree BST, ElementType X ){
    BinTree temp;
    if( !BST ) printf("Not Found\n");
    else{
        if(X < BST -> Data) BST -> Left = Delete(BST -> Left, X);
        else if(X > BST -> Data) BST -> Right = Delete(BST -> Right, X);
        else{
            if(BST -> Left && BST -> Right){
                //关键!
                //不需要真的删除节点,只需要找个右子树上的最小值来替代它
                //然后删除右子树上的最小值即可!
                temp = FindMin(BST->Right);
                BST -> Data = temp ->Data;
                BST -> Right= Delete(BST -> Right,BST -> Data);
            }
            else{
                temp = BST;
                if( !BST -> Left ) BST = BST -> Right;
                else if( !BST -> Right ) BST = BST -> Left;
                free(temp);
            }
        }
    }
    return BST;
}
Position Find( BinTree BST, ElementType X ){
    //这个写法不太能理解
    //找到BST之后,就返回上层,但是上层怎么继续返回上层呢?怎么把找到的位置返回给最上层?
    if( BST ){
        if(X == BST -> Data) return BST;
        else if(X < BST -> Data) Find(BST -> Left, X);
        else if(X > BST -> Data) Find(BST -> Right, X);
    }
    else return NULL;
    //这个写法我能理解
    /*while( BST ){
        if(X == BST -> Data){
            printf("%d\n", BST -> Data);
            return BST;
        }
        else if(X < BST -> Data) BST = Find(BST -> Left, X);
        else if(X > BST -> Data) BST = Find(BST -> Right, X);
    }
    return NULL;*/
}
Position FindMin( BinTree BST ){
    if( BST ){
        if( !BST -> Left ) return BST;
        else FindMin(BST -> Left);
    }
}
Position FindMax( BinTree BST ){
    if( BST ){
        if( !BST -> Right ) return BST;
        else FindMax(BST -> Right);
    }
}

编程题

01-复杂度1 最大子列和问题(分数20)

题目要求
给定K个整数组成的序列{ N1, N2, …, NK},“连续子列”被定义为{ Ni, Ni+1, …, Nj},其中 1≤i≤j≤K。“最大子列和”则被定义为所有连续子列元素的和中最大者。例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20。现要求你编写程序,计算给定整数序列的最大子列和。
本题旨在测试各种不同的算法在各种数据情况下的表现。各组测试数据特点如下:

  • 数据1:与样例等价,测试基本正确性;
  • 数据2:102个随机整数;
  • 数据3:103个随机整数;
  • 数据4:104个随机整数;
  • 数据5:105个随机整数;

输入格式
输入第1行给出正整数K (≤100000);第2行给出K个整数,其间以空格分隔。

输出格式
在一行中输出最大子列和。如果序列中所有整数皆为负数,则输出0。

输入样例:

6
-2 11 -14 13 -5 -2

输出样例:

20

代码

/*思路:
从头开始连加,每加一个数,检查和,若和为负则舍去(因为和为负继续往下加不会比现在的数更大),然后重新在和为负的下一位开始加。
如果是正数则可以继续往下加
*/
#include<stdio.h>
#include<stdlib.h>

void getmax(int n, int a[]);

int main(){
    int n;
    scanf("%d",&n);
    int a[n];
    for(int i=0;i<n;i++) scanf("%d",a+i);
    getmax(n,a);
}

void getmax(int n, int a[]){
    int sum = 0, max = 0;
    for(int i = 0; i < n; i++){
        sum += a[i];
        if(sum >= max) max = sum;
        else if(sum <= 0) sum = 0;
    }
    printf("%d",max);
}

01-复杂度2 Maximum Subsequence Sum(分数 25)

题目要求
Given a sequence of K integers { N1, N2, …, NK}. A continuous subsequence is defined to be{ Ni, Ni+1, …, Nj}, where 1≤i≤j≤K. The Maximum Subsequence is the continuous subsequence which has the largest sum of its elements. For example, given sequence { -2, 11, -4, 13, -5, -2 }, its maximum subsequence is { 11, -4, 13 } with the largest sum being 20.
Now you are supposed to find the largest sum, together with the first and the last numbers of the maximum subsequence.

Input Specification:
Each input file contains one test case. Each case occupies two lines. The first line contains a positive integer K (≤10000). The second line contains K numbers, separated by a space.

Output Specification:
For each test case, output in one line the largest sum, together with the first and the last numbers of the maximum subsequence. The numbers must be separated by one space, but there must be no extra space at the end of a line. In case that the maximum subsequence is not unique, output the one with the smallest indices i and j (as shown by the sample case). If all the K numbers are negative, then its maximum sum is defined to be 0, and you are supposed to output the first and the last numbers of the whole sequence.

Sample Input:

10
-10 1 2 3 4 -5 -23 3 7 -21

Sample Onput:

10 1 4

代码

//注意情况:
//全是负数:输出0,序列的第一个数字,序列的最后一个数字
//全是负数和0:输出0,0,0
//如果有多个相同的最大和存在,输出序列号最小的,这是个坑,要注意!
//特别的,注意1 -1 0 2 3,应输出5 1 3,而不是5 2 3

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

void getmax(int n, int a[]);

int main(){
    int n;
    scanf("%d",&n);
    int a[n];
    for(int i=0;i<n;i++) scanf("%d",a+i);
    getmax(n,a);
}

void getmax(int n, int a[]){
    int sum = 0, max = 0;
    int maxstart = 0, maxend = 0;
    int cnt1 = 0, cnt2 = 0;//分别负数个数和非正数个数
    for(int i = 0; i < n; i++){
        if(a[i]<=0)
        {
            if(a[i]<0)
            {
                cnt1++;
            }
            cnt2++;
        }
        sum += a[i];
        if(sum > max){
            max = sum;
            maxend = i;
        }
        else if(sum <= 0){
            sum = 0;
        }
    }
    if(cnt1 == n) printf("%d %d %d", 0, a[0], a[n-1]);
    else if(cnt2 == n) printf("%d %d %d", 0, 0, 0);
    sum = 0;
    for(int i = maxend; i >= 0; i--){
        sum += a[i];
        if(sum == max){
            maxstart = i;
        }
    }
    if(max > 0) printf("%d %d %d",max,a[maxstart],a[maxend]);
}

02-线性结构2 一元多项式的乘法与加法运算(分数20)

题目要求
设计函数分别求两个一元多项式的乘积与和。

输入格式
输入分2行,每行分别先给出多项式非零项的个数,再以指数递降方式输入一个多项式非零项系数和指数(绝对值均为不超过1000的整数)。数字间以空格分隔。

输出格式
输出分2行,分别以指数递降方式输出乘积多项式以及和多项式非零项的系数和指数。数字间以空格分隔,但结尾不能有多余空格。零多项式应输出0 0。

输入样例:

4 3 4 -5 2  6 1  -2 0
3 5 20  -7 4  3 1

输出样例:

15 24 -25 22 30 21 -10 20 -21 8 35 6 -33 5 14 4 -15 3 18 2 -6 1
5 20 -4 4 -5 2 9 1 -2 0

代码

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

typedef struct PolyNode *Polynomial;
struct PolyNode{
    int coef;
    int expon;
    Polynomial link;
};

Polynomial ReadPoly();
void Attach(int c,int e,Polynomial *PRear);
Polynomial Mult(Polynomial P1,Polynomial P2);
Polynomial Add(Polynomial P1,Polynomial P2);
void PrintPoly(Polynomial P);

int main(){
    Polynomial P1,P2,PP,PS;
    
    P1 = ReadPoly();
    P2 = ReadPoly();
    //多项式相乘
    PP = Mult(P1,P2);
    PrintPoly(PP);
    //多项式相加
    PS = Add(P1,P2);
    PrintPoly(PS);
    return 0;
}

Polynomial ReadPoly(){
    Polynomial P,Rear,temp;
    int N,c,e;
    scanf("%d",&N);

    P = (Polynomial)malloc(sizeof(struct PolyNode));
    P->link = NULL;//创造一个空节
    Rear = P;//赋予Rear初值

    while(N--){
        scanf("%d%d",&c,&e);
        Attach(c,e,&Rear);//直接将Rear的地址传入
    }
    temp = P;//删除临时生成的头部空节点
    P = temp->link;
    free(temp);

    return P;
}

void Attach(int c,int e,Polynomial *PRear){
    Polynomial P;
    P = (Polynomial)malloc(sizeof(struct PolyNode));
    P -> coef = c;
    P -> expon = e;
    P -> link = NULL;
    (*PRear) -> link = P;
    *PRear = P;
}

void PrintPoly(Polynomial P){
    int flag = 0;//用于判断是不是首项
    if(!P){    //已经打印完,结尾要将零多项式进行输出
        printf("0 0\n");
        return;
    }
    while(P){
        if(!flag) flag = 1;
        else printf(" ");
        printf("%d %d",P->coef,P->expon);
        P = P -> link;
    }
    printf("\n");
}

//多项式相加
Polynomial Add(Polynomial P1,Polynomial P2){
    Polynomial t1,t2,temp;//用于接收两个多项式
    t1 = P1;
    t2 = P2;
    Polynomial P,PRear;//用于存储相加后的多项式
    P = (Polynomial)malloc(sizeof(struct PolyNode));
    P -> link = NULL;
    PRear = P;//接收相加后多项式的开头,不能改变原值!
    
    while(t1&&t2){
        if(t1 -> expon > t2 -> expon){
            Attach(t1 -> coef, t1 -> expon, &PRear);
            t1 = t1 -> link;
        }
        else if(t1 -> expon < t2 -> expon){
            Attach(t2 -> coef, t2 -> expon, &PRear);
            t2 = t2 -> link;
        }
        else if(t1 -> expon == t2 -> expon){
            int sum_coef = t1 -> coef + t2 -> coef;
            if(sum_coef) Attach(sum_coef, t1 -> expon, &PRear);
            t1 = t1 -> link;
            t2 = t2 -> link;
        }
    }
    //当两个多项式有一个加完了,有一个没加完,将没加完的多项式结尾进行拼接
    while(t1){
        Attach(t1 -> coef, t1 -> expon, &PRear);
        t1 = t1 -> link;
    }
    while(t2){
        Attach(t2 -> coef, t2 -> expon, &PRear);
        t2 = t2 -> link;
    }
    PRear -> link = NULL;
    temp = P;//将头部空节点删除
    P = P -> link;
    free(temp);
    return P;
}

Polynomial Mult(Polynomial P1,Polynomial P2){
    if( !P1 || !P2 ) return NULL;
    int c,e;
    Polynomial t1,t2,P,PRear,temp;
    t1 = P1;
    t2 = P2;
    temp = (Polynomial)malloc(sizeof(struct PolyNode));
    P = (Polynomial)malloc(sizeof(struct PolyNode));
    P -> link = NULL;
    PRear = P;//接收相加后多项式的开头,不能改变原值!
    //先将t1的第一项和t2的所有项进行相乘,会得到初始的多项式,方便后续的其他项按指数大小进行排序插入
    while(t2){
        if(t1 -> coef * t2 -> coef) Attach(t1 -> coef * t2 -> coef, t1 -> expon + t2 -> expon, &PRear); 
        t2 = t2 -> link;
    }
    t1 = t1 -> link;
    while(t1){
        t2 = P2;//注意,t2每次都要从头开始乘!!!
        PRear = P;
        while(t2){
            c = t1 -> coef * t2 -> coef;
            e = t1 -> expon + t2 -> expon;
            while(PRear -> link && PRear -> link -> expon > e) PRear = PRear -> link;
                if(PRear -> link && e == PRear -> link -> expon){
                    if(PRear -> link -> coef + c) PRear -> link -> coef += c;
                    else{//相加为0
                        temp = PRear -> link;
                        PRear -> link = temp -> link;
                        free(temp);//将头部空节点删除
                    }
                }
                else{
                    temp = (Polynomial)malloc(sizeof(struct PolyNode));
                    temp -> coef = c;
                    temp -> expon = e;
                    temp -> link = PRear -> link;
                    PRear -> link = temp;
                    PRear = PRear -> link;
                }
            t2 = t2 -> link;
        }
        t1 = t1 -> link;
    }
    temp = (Polynomial)malloc(sizeof(struct PolyNode));
    temp = P;
    P = P -> link;
    free(temp);//将头部空节点删除
    return P;
}

02-线性结构3 Reversing Linked List(分数 25)

题目要求
Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elements on L. For example, given L being 1→2→3→4→5→6, if K=3, then you must output 3→2→1→6→5→4; if K=4, you must output 4→3→2→1→5→6.

Input Specification:
Each input file contains one test case. For each case, the first line contains the address of the first node, a positive N (≤105) which is the total number of nodes, and a positive K (≤N) which is the length of the sublist to be reversed. The address of a node is a 5-digit nonnegative integer, and NULL is represented by -1.
Then N lines follow, each describes a node in the format:

Address Data Next

Output Specification:
For each case, output the resulting ordered linked list. Each node occupies a line, and is printed in the same format as in the input.

Sample Input:

00100 6 4
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218

Sample Onput:

00000 4 33218
33218 3 12309
12309 2 00100
00100 1 99999
99999 5 68237
68237 6 -1

代码
法一: 将每个元素的指向进行逆转。分别将逆转成功的结点设为new,还未逆转的设为old,然后进行指针指向的设置。
在这里插入图片描述

//法一:逐个反转
#include<stdio.h>
#include<stdlib.h>
#define MAX 100005

struct Node {
    int add, data, next;//分别存放本结点的地址、数据和下一个节点的地址
}List[MAX];

int ReadList(int first_add, int l, struct Node List[]);
void PrintList(int l, struct Node List[], int first_add);
int ReverseList(int k, struct Node List[], int head);

int main() {
    int first_add = MAX - 1;//设置一个不在地址范围内的空链表
    List[first_add].add = first_add;
    int l0, k;
    scanf("%d %d %d", &List[first_add].next, &l0, &k);
    //l0为初始输入的结点个数,其中包含在和不在链表中的节点
    //所以需要把不在链表上的节点进行剔除,即不把其地址存入到add当中
    int l = ReadList(List[first_add].next, l0, List);
    
    int head = first_add;
    for(int i = 0; i < l / k; i++) head = ReverseList(k, List, head);
    
    PrintList(l, List, first_add);

    return 0;
}

int ReverseList(int k, struct Node List[], int head){
    int new, old, temp;
    new = List[head].next, old = List[new].next;
    int re = new;
    for(int i = 1; i < k; i++){
        temp = List[old].next;
        List[old].next = new;
        new = old;
        old = temp;
    }
    List[List[head].next].next = old;
    List[head].next = new;
    
    return re;
}

int ReadList(int first_add, int l0, struct Node List[]){
    int address, data, next;
    for (int i = 0; i < l0; i++) {
        scanf("%d %d %d", &address, &data, &next);
        List[address].add = address;
        List[address].data = data;
        List[address].next = next;
    }
    //按照顺序存放地址
    int l = 0;//l用于记录在链表中数据的个数
    while(first_add != -1){
        first_add = List[first_add].next;
        l++;
    }
    return l;
}

void PrintList(int l, struct Node List[], int first_add){
    int add = List[first_add].next;
    int i = 0;
    while(List[add].next != -1){
        printf("%05d %d %05d\n", List[add].add, List[add].data, List[add].next);
        add = List[add].next;
    }
    printf("%05d %d -1\n", List[add].add, List[add].data);
}

法二:

法二:进行翻转
#include<stdio.h>
#include<stdlib.h>
#define MAX 100005

struct Node {
    int data, next;
}List[MAX];

int ReadList(int first_add, int l, struct Node List[], int add[]);
void PrintList(int l, struct Node List[], int add[]);
void ReverseList(int l, int k, struct Node List[], int add[]);

int main() {
    int first_add, l0, k;
    scanf("%d %d %d", &first_add, &l0, &k);
    int add[l0];
    //l0为初始输入的结点个数,其中包含在和不在链表中的节点
    //所以需要把不在链表上的节点进行剔除,即不把其地址存入到add当中
    int l = ReadList(first_add, l0, List, add);
    ReverseList(l, k, List, add);
    PrintList(l, List, add);

    return 0;
}

int ReadList(int first_add, int l0, struct Node List[], int add[]){
    int address, data, next;
    for (int i = 0; i < l0; i++) {
        scanf("%d %d %d", &address, &data, &next);
        List[address].data = data;
        List[address].next = next;
    }
    //按照顺序存放地址
    int l = 0;
    while(first_add != -1){
        add[l++] = first_add;
        first_add = List[first_add].next;
    }
    return l;
}

void PrintList(int l, struct Node List[], int add[]){
    for(int i = 0; i < l - 1; i++){
        printf("%05d %d %05d\n", add[i], List[add[i]].data, List[add[i]].next);
    }
    printf("%05d %d -1\n", add[l-1], List[add[l-1]].data);
}

void ReverseList(int l, int k, struct Node List[], int add[]){
    int t = 0, turn = l / k;
    int temp = 0;
    for(int i = 0; i < turn * k; i += k){
        for(int j = 0; j < k / 2; j++){
            temp = add[i + j];
            add[i + j] = add[i + k - j -1];
            add[i + k - j - 1] = temp;
        }
    }
    
    //调整列表的结尾处地址
    for (int i = 0; i < l - 1; i++) List[add[i]].next = add[i + 1];
    List[add[l - 1]].next = -1;
}

02-线性结构4 Pop Sequence(分数 25)

题目要求
Given a stack which can keep M numbers at most. Push N numbers in the order of 1, 2, 3, …, N and pop randomly. You are supposed to tell if a given sequence of numbers is a possible pop sequence of the stack. For example, if M is 5 and N is 7, we can obtain 1, 2, 3, 4, 5, 6, 7 from the stack, but not 3, 2, 1, 7, 5, 6, 4.

Input Specification:
Each input file contains one test case. For each case, the first line contains 3 numbers (all no more than 1000): M (the maximum capacity of the stack), N (the length of push sequence), and K (the number of pop sequences to be checked). Then K lines follow, each contains a pop sequence of N numbers. All the numbers in a line are separated by a space.

Output Specification:
For each pop sequence, print in one line “YES” if it is indeed a possible pop sequence of the stack, or “NO” if not.

Sample Input:

5 7 5
1 2 3 4 5 6 7
3 2 1 7 5 6 4
7 6 5 4 3 2 1
5 6 4 3 7 2 1
1 7 6 5 4 3 2

Sample Onput:

YES
NO
NO
YES
NO

代码

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

#define Maxsize 1000//元素的最大容量
typedef struct Node{
    int Top;//栈顶
    int Data[Maxsize];//元素
    int Capacity;//容量
}*Stack;

int judge(int m,int n, int array[]);

int main(){
    int m = 0, n = 0, k = 0;
    scanf("%d %d %d", &m, &n, &k);
    int array[n];
    while( k-- ){
        for(int i = 0; i < n; i++) scanf("%d",&array[i]);
        if(judge(m,n,array)) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

int judge(int m,int n, int array[]){
    int count = 0;
    if(array[0] > m) return 0;//如果开头大于5,则直接返回NO
    Stack s = (Stack)malloc(sizeof(struct Node));
    s -> Capacity = m;
    s -> Top = -1;
    for(int i = 1; i <= n; i++){
        if(s -> Capacity == s -> Top +1) return 0;
        else s -> Data[ ++ s -> Top ] = i;
        while(s -> Data[s -> Top] == array[count]){
            count += 1;
            s -> Top --;
        }
    }
    if(n == count) return 1;
    else return 0;
}

03-树1 树的同构(分数25)

题目要求
给定两棵树 T1 和 T2。如果T1可以通过若干次左右孩子互换就变成 T2,则我们称两棵树是“同构”的。例如图1给出的两棵树就是同构的,因为我们把其中一棵树的结点A、B、G的左右孩子互换后,就得到另外一棵树。而图2就不是同构的。
图1:
在这里插入图片描述
图2:
在这里插入图片描述
现给定两棵树,请你判断它们是否是同构的。

输入格式
输入给出2棵二叉树的信息。对于每棵树,首先在一行中给出一个非负整数 n (≤10),即该树的结点数(此时假设结点从 0 到 n−1 编号);随后 n 行,第 i 行对应编号第 i 个结点,给出该结点中存储的 1 个英文大写字母、其左孩子结点的编号、右孩子结点的编号。如果孩子结点为空,则在相应位置上给出 “-”。给出的数据间用一个空格分隔。注意:题目保证每个结点中存储的字母是不同的。

输出格式
如果两棵树是同构的,输出“Yes”,否则输出“No”。

输入样例1:

8
A 1 2
B 3 4
C 5 -
D - -
E 6 -
G 7 -
F - -
H - -
8
G - 4
B 7 6
F - -
A 5 1
H - -
C 0 -
D - -
E 2 -

输出样例1:

Yes

输入样例2:

8
B 5 7
F - -
A 0 3
C 6 -
H - -
D - -
G 4 -
E 1 -
8
D 6 -
B 5 -
E - -
H - -
C 0 2
G - 3
F - -
A 1 4

输出样例2:

No

代码

#include<iostream>
#include<string>
#define ElementType char
#define add int
#define MAX 10
#define Null -1

using namespace std;

struct Tree{
    ElementType data;
    add left;
    add right;
}T1[MAX], T2[MAX];

Tree BuildTree(Tree T[]);
int Isomorphic(Tree R1, Tree R2);

int main(){
    //读入数据,构造树,返回树的根节点
    Tree R1, R2;//根节点
    R1 = BuildTree(T1);
    R2 = BuildTree(T2);
    //判断2棵二叉树是否同构
    if(Isomorphic(R1,R2)) cout << "Yes" << endl;
    else cout<< "No" << endl;
    
    return 0;
}

Tree BuildTree(struct Tree T[]){
    Tree Root;//根节点
    int n;
    cin >> n;
    if(!n){
        Root.left = Null;
        Root.right = Null;
        return Root;
    }//树为空
    char data;
    char left, right;//因为可能出现"-",所以先统一输入为字符串
    //!!!!关键错误:数组没有给长度!!!给了初值0,则默认为长度为1!
    //int check[] = {0};
    int check[n] = {0};//用于判定谁是根节点,在左右节点中没出现过的即为根节点
    for(int i = 0; i < n; i++){
        cin >> data >> left >> right;//统一先输入为字符串
        T[i].data = data;
        if(left != '-'){
            T[i].left = left - '0';//转化为整数类型
            check[T[i].left] = 1;
        }
        else T[i].left = Null;
        if(right != '-'){
            T[i].right = right - '0';//转化为整数类型
            check[T[i].right] = 1;
        }
        else T[i].right = Null;
    }
    for(int j = 0; j < n; j++){
        if( check[j] != 1 ){
            Root = T[j];
            break;
        }
    }
    return Root;
}

int Isomorphic(Tree R1, Tree R2){
    if(R1.data != R2.data)
        return 0;//R1和R2节点名不同
    if(R1.left == Null && R1.right == Null && R2.left == Null && R2.right == Null)
        return 1;//R1和R2均为空则同构,而且根节点名相同!
    if((R1.left == Null && R1.right == Null) && (R2.left != Null || R2.right != Null))
        return 0;//R1空R2不空则不同构
    if((R1.left != Null || R1.right != Null) && (R2.left == Null && R2.right == Null))
        return 0;//R1不为空R2空则不同构
    if((R1.left != Null && R1.right == Null) && (R2.left != Null && R2.right == Null))
        return(Isomorphic(T1[R1.left], T2[R2.left]));//R1和R2左边均不为空
    if((R1.left == Null && R1.right != Null) && (R2.left == Null && R2.right != Null))
        return(Isomorphic(T1[R1.right], T2[R2.right]));//R1和R2右边均不为空
    if((R1.left != Null && R1.right == Null) && (R2.left == Null && R2.right != Null))
        return(Isomorphic(T1[R1.left], T2[R2.right]));//R1左不空右空和R2左空右不空
    if((R1.left == Null && R1.right != Null) && (R2.left != Null && R2.right == Null))
        return(Isomorphic(T1[R1.right], T2[R2.left]));//R1左空右不空和R2左不空右空
    if((R1.left != Null && R1.right != Null) && (R2.left != Null && R2.right != Null)){
        if(T1[R1.left].data == T2[R2.left].data)
            return((Isomorphic(T1[R1.left], T2[R2.left])) && (Isomorphic(T1[R1.right], T2[R2.right])));
        else
            return((Isomorphic(T1[R1.left], T2[R2.right])) && (Isomorphic(T1[R1.right], T2[R2.left])));
    }
}

03-树2 List Leaves(分数 25)

题目要求
Given a tree, you are supposed to list all the leaves in the order of top down, and left to right.

Input Specification:
Each input file contains one test case. For each case, the first line gives a positive integer N (≤10) which is the total number of nodes in the tree – and hence the nodes are numbered from 0 to N−1. Then N lines follow, each corresponds to a node, and gives the indices of the left and right children of the node. If the child does not exist, a “-” will be put at the position. Any pair of children are separated by a space.

Output Specification:
For each test case, print in one line all the leaves’ indices in the order of top down, and left to right. There must be exactly one space between any adjacent numbers, and no extra space at the end of the line.

Sample Input:

8
1 -
- -
0 -
2 7
- -
- -
5 -
4 6

Sample Onput:

4 1 5

代码

/*
思路:
1、构造结点结构体,包含该结点的结点序列,左右儿子所在序列
2、读入树后,判定头结点
3、函数:构造树函数、层序遍历读取叶结点
*/
#include<iostream>
#include<queue>
#define MAX 10
#define Null -1
using namespace std;

//构造结点的结构体
struct Tree{
    int data;
    int left;
    int right;
}T[MAX];

Tree BuildTree(int n, Tree T[]);
void PrintLeaves(int n, Tree R);

int main(){
    int n;
    cin >> n;
    Tree R;
    R = BuildTree(n, T);
    PrintLeaves(n, R);
    
    return 0;
}

void PrintLeaves(int n, Tree R){
    int results[n];//用于存放结果
    for(int a = 0; a < n; a++) results[a] = -1;
    queue<Tree> q;//构造队列
    q.push(R);
    int i = 0;
    while(!q.empty()){
        if(q.front().left != Null) q.push(T[q.front().left]);
        if(q.front().right != Null) q.push(T[q.front().right]);
        if(q.front().left == Null && q.front().right == Null){
            results[i++] = q.front().data;
        }
        q.pop();
    }
    for(int j = 0; j < i - 1; j++){
        cout << results[j] <<" "; 
    }
    cout << results[i - 1] << endl;
}

Tree BuildTree(int n, Tree T[]){
    Tree Root;
    if(!n){//树只有一个节点
        Root.left = Null;
        Root.right = Null;
        return Root;
    }
    char left, right;
    int check[n] = {0};//用于判定谁是头结点
    //i用于记录叶结点的个数
    for(int i = 0; i < n; i++){
        cin >> left >> right;
        T[i].data = i;
        if(left != '-'){
            T[i].left = left - '0';
            check[T[i].left] = 1;
        }
        else T[i].left = Null;
        if(right != '-'){
            T[i].right = right - '0';
            check[T[i].right] = 1;
        }
        else T[i].right = Null;
    }

    for(int j = 0; j < n; j++){
        if(check[j] == 0){
            Root = T[j];
            break;
        }
    }
    return Root;
}

03-树3 Tree Traversals Again(分数 25)

题目要求
An inorder binary tree traversal can be implemented in a non-recursive way with a stack. For example, suppose that when a 6-node binary tree (with the keys numbered from 1 to 6) is traversed, the stack operations are: push(1); push(2); push(3); pop(); pop(); push(4); pop(); pop(); push(5); push(6); pop(); pop(). Then a unique binary tree (shown in Figure 1) can be generated from this sequence of operations. Your task is to give the postorder traversal sequence of this tree.
在这里插入图片描述
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤30) which is the total number of nodes in a tree (and hence the nodes are numbered from 1 to N). Then 2N lines follow, each describes a stack operation in the format: “Push X” where X is the index of the node being pushed onto the stack; or “Pop” meaning to pop one node from the stack.

Output Specification:
For each test case, print the postorder traversal sequence of the corresponding tree in one line. A solution is guaranteed to exist. All the numbers must be separated by exactly one space, and there must be no extra space at the end of the line.

Sample Input:

6
Push 1
Push 2
Push 3
Pop
Pop
Push 4
Pop
Pop
Push 5
Push 6
Pop
Pop

Sample Onput:

3 4 2 6 5 1

代码

/*
提示:不用建树也能做出来
push和pop的顺序分别是前序和中序
*/
#include<iostream>
#include<string>
#include<stack>
#define MAX 30
using namespace std;

void ReadTree(int n, int Preorder[], int Inorder[]);
int PrintPostorder(int n, int root, int start, int end, int Preorder[], int Inorder[]);
int k = 0;

int main(){
    int n;
    cin >> n;
    int Preorder[n] = {0};
    int Inorder[n] = {0};
    ReadTree(n, Preorder, Inorder);
    int root = 0, start = 0, end = n - 1;
    PrintPostorder(n, root, start, end, Preorder, Inorder);
    return 0;
}

int PrintPostorder(int n, int root, int start, int end, int Preorder[], int Inorder[]){
    //root为前序的根节点
    //start和end为中序当前所在根节点的开头和结尾
    if(start > end) return 1;
    int i = start;
    while(i < end && Preorder[root] != Inorder[i]) i++;//在中序中找前序的根节点
    PrintPostorder(n, root + 1, start, i - 1, Preorder, Inorder);//左子树
    PrintPostorder(n, root - start + i + 1, i + 1, end, Preorder, Inorder);//右子树
    /*左子树的根节点为root + 1,是因为是前序,根节点后马上跟的就是左子树的结点
    但是左子树遍历返回后,root又变为左子树上一级的根节点,所以 + 1还是左子树的结点,而非右子树,所以要重新计算
    特别注意右子树的根结点
    左子树的长度为i - start
    则右子树的根节点所在处即为根节点 + 左子树的长度 + 1*/
    if(k != n - 1){
        cout << Inorder[i] << " ";
        k++;
    }
    else if(k == n - 1){
        cout << Inorder[i] << endl;
    }
    return 1;
}

//读取前序和中序
void ReadTree(int n, int Preorder[], int Inorder[]){
    stack<int> mystack;
    string s;
    int data;
    int a = 0, b = 0;
    for(int i = 0; i < 2 * n; i++){
        cin >> s;
        if(s == "Push"){
            cin >> data;
            Preorder[a++] = data;
            mystack.push(data);
        }
        else if(s == "Pop"){
            Inorder[b++] = mystack.top();
            mystack.pop();
        }
    }
}

04-树4 是否同一棵二叉搜索树(分数25)

题目要求
给定一个插入序列就可以唯一确定一棵二叉搜索树。然而,一棵给定的二叉搜索树却可以由多种不同的插入序列得到。例如分别按照序列{2, 1, 3}和{2, 3, 1}插入初始为空的二叉搜索树,都得到一样的结果。于是对于输入的各种插入序列,你需要判断它们是否能生成一样的二叉搜索树。

输入格式
输入包含若干组测试数据。每组数据的第1行给出两个正整数N (≤10)和L,分别是每个序列插入元素的个数和需要检查的序列个数。第2行给出N个以空格分隔的正整数,作为初始插入序列。随后L行,每行给出N个插入的元素,属于L个需要检查的序列。
简单起见,我们保证每个插入序列都是1到N的一个排列。当读到N为0时,标志输入结束,这组数据不要处理。

输出格式
对每一组需要检查的序列,如果其生成的二叉搜索树跟对应的初始序列生成的一样,输出“Yes”,否则输出“No”。

输入样例:

4 2
3 1 4 2
3 4 1 2
3 2 4 1
2 1
2 1
1 2
0

输出样例:

Yes
No
No

代码

#include <iostream>
using namespace std;

//结点类
struct TreeNode{
    int data;
    TreeNode *left, *right;
    int flag;
};
typedef TreeNode *Tree;

Tree InsertTree(Tree tree, int data){
    //如果树为空,则建造空节点
    if(!tree){
        tree = new(TreeNode);
        tree -> data = data;
        tree -> left = NULL;
        tree -> right = NULL;
        tree -> flag = 0;
    }
    else if(data < tree -> data) tree -> left = InsertTree(tree -> left, data);
    else if(data > tree -> data) tree -> right = InsertTree(tree -> right, data);
    return tree;
}

int check(Tree tree, int data){
    if(tree -> flag){//曾经经过该点
        if(data < tree -> data) return check(tree -> left, data);
        else if(data > tree -> data) return check(tree -> right, data);
        else return 0;
    }
    else{
        if(data == tree -> data){
            tree -> flag = 1;
            return 1;
        }
        else return 0;
    }
}

void Resettree(Tree tree){
    if(tree -> left) Resettree(tree -> left);
    if(tree -> right) Resettree(tree -> right);
    tree -> flag = 0;
}

int main(){
    int n, l;
    int data;
    //没读到结束标志位
    while( cin >> n && n ){
        cin >> l;
        Tree tree = NULL;
        for(int i = 0; i < n; i++){
            cin >> data;
            tree = InsertTree(tree, data);
        }
        for(int i = 0; i < l; i++){
            bool judge_flag = true;
            Resettree(tree);
            for(int j = 0; j < n; j++){
                cin >> data;
                if( !check(tree, data) ) judge_flag = false;
            }
            //建参考二叉搜索树
            //需要判断的树就不再进行建树,直接逐个进行判断
            judge_flag?cout<<"Yes"<<endl:cout<<"No"<<endl;
        }
    }
    return 0;
}

04-树5 Root of AVL Tree(分数 25)

题目要求
An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; if at any time they differ by more than one, rebalancing is done to restore this property. Figures 1-4 illustrate the rotation rules.
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
Now given a sequence of insertions, you are supposed to tell the root of the resulting AVL tree.

Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤20) which is the total number of keys to be inserted. Then N distinct integer keys are given in the next line. All the numbers in a line are separated by a space.

Output Specification:
For each test case, print the root of the resulting AVL tree in one line.

Sample Input1:

5
88 70 61 96 120

Sample Onput1:

70

Sample Input2:

7
88 70 61 96 120 90 65

Sample Onput2:

88

代码

#include<iostream>
#include<algorithm>
using namespace std;

typedef struct TreeNode *Tree;
struct TreeNode{
    int data;
    Tree left;
    Tree right;
    int height;
};

int GetHight( Tree tree );//获得该节点左右子树的高度
Tree InsertTree( Tree tree, int data );
Tree SingleLeftRotation( Tree tree );
Tree DoubleLeftRightRotation ( Tree tree );
Tree SingleRightRotation( Tree tree );
Tree DoubleRightLeftRotation( Tree tree );

int main(){
    int n;
    cin >> n;
    Tree tree = NULL;
    if(n){
        for(int i = 0; i < n; i++){
            int data;
            cin >> data;
            tree = InsertTree( tree, data);
        }
        cout << tree -> data << endl;
    }
    else cout << "0" << endl;
    return 0;
}

int GetHight( Tree tree ){
    int hl, hr;
    if(tree){
        hl = GetHight(tree -> left);
        hr = GetHight(tree -> right);
        tree -> height = max(hl, hr) + 1;
    }
    else return 0;
    return tree -> height;
}

Tree InsertTree( Tree tree, int data ){
    if( !tree ){
        tree = (Tree)malloc(sizeof(struct TreeNode));
        tree -> data = data;
        tree -> left = NULL;
        tree -> right = NULL;
        tree -> height = 0;
    }
    else if(data > tree -> data){
        tree -> right = InsertTree(tree -> right, data);
        if((GetHight(tree -> right) - GetHight(tree -> left)) == 2){
            if( data > tree -> right ->data ) tree = SingleRightRotation(tree);
            else tree = DoubleRightLeftRotation(tree);
        }
    }
    else if(data < tree -> data){
        tree -> left = InsertTree(tree -> left, data);
        if((GetHight(tree -> left) - GetHight(tree -> right)) == 2){
            if( data < tree -> left -> data) tree = SingleLeftRotation(tree);
            else tree = DoubleLeftRightRotation(tree);
        }
    }
    tree -> height = max(GetHight(tree -> left), GetHight(tree -> right)) + 1;
    return tree;
}

Tree SingleLeftRotation ( Tree tree ){
    Tree temp;
    temp = tree -> left;
    tree -> left = temp -> right;//感觉这个没必要,因为如果temp的右边有数据,那么tree早都是不平衡的了
    temp -> right = tree;

    tree -> height = max(GetHight(tree -> left), GetHight(tree -> right)) + 1;
    temp -> height = max(GetHight(temp -> left), tree -> height) + 1;

    return temp;
}

Tree DoubleLeftRightRotation ( Tree tree ){
    tree -> left = SingleRightRotation( tree -> left);
    return SingleLeftRotation( tree );
}

Tree SingleRightRotation ( Tree tree ){
    Tree temp;
    temp = tree -> right;
    tree -> right = temp -> left;//感觉这个没必要,因为如果temp的右边有数据,那么tree早都是不平衡的了
    temp -> left = tree;

    tree -> height = max(GetHight(tree -> left), GetHight(tree -> right)) + 1;
    temp -> height = max(tree -> height, GetHight(temp -> right)) + 1;

    return temp;
}
Tree DoubleRightLeftRotation( Tree tree ){
    tree -> right = SingleLeftRotation( tree -> right);
    return SingleRightRotation( tree );
}

04-树6 Complete Binary Search Tree(分数 30)

题目要求
A Binary Search Tree (BST) is recursively defined as a binary tree which has the following properties:

  • The left subtree of a node contains only nodes with keys less than the node’s key.
  • The right subtree of a node contains only nodes with keys greater than or equal to the node’s key.
  • Both the left and right subtrees must also be binary search trees.
    A Complete Binary Tree (CBT) is a tree that is completely filled, with the possible exception of the bottom level, which is filled from left to right.
    Now given a sequence of distinct non-negative integer keys, a unique BST can be constructed if it is required that the tree must also be a CBT. You are supposed to output the level order traversal sequence of this BST.

Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤1000). Then N distinct non-negative integer keys are given in the next line. All the numbers in a line are separated by a space and are no greater than 2000.

Output Specification:
For each test case, print in one line the level order traversal sequence of the corresponding complete binary search tree. All the numbers in a line must be separated by a space, and there must be no extra space at the end of the line.

Sample Input:

10
1 2 3 4 5 6 7 8 9 0

Sample Onput:

6 3 8 1 5 7 9 0 2 4

代码
暂时还没写出来

  • 30
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值