PAT_MOOC-陈越等-数据结构

函数题

01-复杂度3 二分查找

代码

Position BinarySearch( List L,ElementType X){
    int min = 1, max = L->Last;
    int M, res, flag = 0;
    for(; min <= max; ){
        M = (min + max) / 2;
        if( X == L->Data[M]){
            res = M;
            flag = 1;
            break;
        }else if( X < L->Data[M]){
            max = M-1;
        }else if( X > L->Data[M]){
            min = M+1;
        }
    }
    if (flag == 0)
        res = NotFound;
        //return NotFound;
    return res;
}

总结&纠错

错误:
1.未理解参数X含义引用;
2.循环内未改变M;
3.原:max=M,min=M;
现:max=M-1,min=M+1;————>运行用时减少;
4.大错误!!flag == 0 写成了 flag = 0

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

代码

List Merge( List L1, List L2 ){
    List pa,pb,p,s;
    /*if(L1->Next == NULL && L2->Next ==NULL ){
        return NULL;
    }*/
    p = (List)malloc(sizeof(struct Node));
    s = p;
    pa = L1->Next;
    pb = L2->Next;
    /*while( pa && pb ){
        switch(compare( pa->Data, pb->Data)){
            case 1:
                s->Next = pa;
                //s = s->Next;
                s = pa;
                pa = pa->Next;
                break;
            case -1:
                s->Next = pb;
                //s = s->Next;
                s = pb;
                pb = pb->Next;
                break;
            case 0:
                s->Next = pa;
                //s = s->Next;
                s = pa;
                pa = pa->Next;
                break;
        }
    }*/

    while( pa && pb){
        if(pa->Data <= pb->Data){
            s->Next = pa;
                //s = s->Next;
            s = pa;
            pa = pa->Next;
        }else{
            s->Next = pb;
            s = pb;
            pb = pb->Next;
        }
    }
    /*while(L1 ){
        s->Next = L1;
    }
    while(L2 ){
        s->Next = L2;
    }*/
    s->Next = pa?pa:pb;
    L1->Next = NULL;
    L2->Next = NULL;
    return p;
}

编程题

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

代码

//算法1、2、3、4的程序代码
#include<stdio.h>
#include<math.h>

int readnum(int *A,int n);
int MaxSubseqSum1(int A[],int N);
int MaxSubseqSum2(int A[],int N);

int Max3( int A, int B, int C );
int DivideAndConquer( int List[], int left, int right);
int MaxSubseqSum3( int List[], int N );//保持与前两种算法同样的接口——算法3

int MaxSubseqSum4( int List[], int N );//保持与前两种算法同样的接口——算法4

int main(){
    int Max_num;
    int res;
    scanf("%d",&Max_num);
    int A[Max_num+1];
    if(readnum(A,Max_num) == 0)
        res = 0;
    else{
        res = MaxSubseqSum4(A,Max_num);
    }
    printf("%d",res);
    return 0;
}

int readnum(int *A, int n){
    int flag = 0;
    for(int i=0; i<n; i++){
        scanf("%d",&A[i]);
        if(A[i] >= 0) flag = 1;
    }
    return flag;
}

/*算法1————O(n^3)*/
int MaxSubseqSum1( int A[],int N){
    int ThisSum,MaxSum = 0;
    int i,j,k;
    for( i = 0; i < N; i++){
        for( j = i; j < N; j++){
            ThisSum = 0;
            for( k = i; k <= j; k++){
                ThisSum += A[k];
            }
            if( ThisSum > MaxSum){
                MaxSum = ThisSum;
            }
        }
    }
    return MaxSum;
}
/*算法2————O(n^2)*/
int MaxSubseqSum2( int A[],int N){
    int ThisSum,MaxSum = 0;
    int i,j;
    for( i = 0; i < N; i++){ /*i是子列左端位置*/
        ThisSum = 0;    /*ThisSum是从A[i]到A[j]的子列和*/
        for( j = i; j < N; j++){/*j是子列右端位置*/
            ThisSum += A[j];
            /*对于相同的i,不同的j,只要在j-1次循环的基础上累加1项即可*/
            if( ThisSum > MaxSum){/*如果刚得到的这个子列和更大*/
                MaxSum = ThisSum;/*则更新结果*/
            }
        }/*j循环结束*/
    }/*i循环结束*/
    return MaxSum;
}

int Max3( int A, int B, int C )
{ /* 返回3个整数中的最大值 */
    return A > B ? A > C ? A : C : B > C ? B : C;
}

int DivideAndConquer( int List[], int left, int right )
{ /* 分治法求List[left]到List[right]的最大子列和 */
    int MaxLeftSum, MaxRightSum; /* 存放左右子问题的解 */
    int MaxLeftBorderSum, MaxRightBorderSum; /*存放跨分界线的结果*/

    int LeftBorderSum, RightBorderSum;
    int center, i;

    if( left == right )  { /* 递归的终止条件,子列只有1个数字 */
        if( List[left] > 0 )  return List[left];
        else return 0;
    }

    /* 下面是"分"的过程 */
    center = ( left + right ) / 2; /* 找到中分点 */
    /* 递归求得两边子列的最大和 */
    MaxLeftSum = DivideAndConquer( List, left, center );
    MaxRightSum = DivideAndConquer( List, center+1, right );

    /* 下面求跨分界线的最大子列和 */
    MaxLeftBorderSum = 0; LeftBorderSum = 0;
    for( i=center; i>=left; i-- ) { /* 从中线向左扫描 */
        LeftBorderSum += List[i];
        if( LeftBorderSum > MaxLeftBorderSum )
            MaxLeftBorderSum = LeftBorderSum;
    } /* 左边扫描结束 */

    MaxRightBorderSum = 0; RightBorderSum = 0;
    for( i=center+1; i<=right; i++ ) { /* 从中线向右扫描 */
        RightBorderSum += List[i];
        if( RightBorderSum > MaxRightBorderSum )
            MaxRightBorderSum = RightBorderSum;
    } /* 右边扫描结束 */

    /* 下面返回"治"的结果 */
    return Max3( MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum );
}

int MaxSubseqSum3( int List[], int N )
{ /* 保持与前2种算法相同的函数接口 */
    return DivideAndConquer( List, 0, N-1 );
}

int MaxSubseqSum4( int A[], int N){
    int ThisSum, MaxSum;
    int i;
    ThisSum = MaxSum = 0;
    for( i = 0; i < N; i++ ){
        ThisSum += A[i];
        if( ThisSum > MaxSum )
            MaxSum = ThisSum;
        else if( ThisSum < 0)
            ThisSum = 0;
    }
    return MaxSum;
}

总结

1.运用四种方法,时间复杂度从大到小,分别是三重循环、二重循环、分治法、在线处理法
2.通过MOOC课程的富文本文档改写,非自己写的。

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

代码

#include<stdio.h>
#include<math.h>

void Readnum( int *A, int K);//读入数组
int Maxsub( int A[], int K, int *head, int *rear);//求最大子列和,返回结构体

int main(){
    int K;
    int res;            //结果
    int rhead,rrear;

    scanf("%d",&K);
    int A[K+1];
    int *head = &rhead;
    int *rear = &rrear;    //结果首尾项
    *head = 1;
    *rear = K;
    Readnum( A, K);
    res = Maxsub( A, K, head, rear);
    printf("%d %d %d", res, A[*head], A[*rear]);

    return 0;
}

void Readnum( int *A, int K){
    for(int i=1; i<=K; i++){
        scanf("%d",&A[i]);
    }

}

int Maxsub( int A[], int K, int *head, int *rear){//求最大子列和
    int ThisSum,Maxsum;
    int i;
    int h,r;
    ThisSum = Maxsum = 0;
    h = 1;
    for( i = 1; i <= K; i++ ){
        ThisSum += A[i];
        if( ThisSum > Maxsum ){
            Maxsum = ThisSum;
            *rear = i;
            *head = h;
        }
        else if( ThisSum < 0){
            ThisSum = 0;
            h = i+1;
        }
        else if( A[i]==0 & ThisSum == 0 & Maxsum == 0){
            *head = i;
            *rear = i;
        }   
    }
    return Maxsum;
}

总结

1.关于指针的定义与初始化需额外加强;
2.数组给出负数和0,应找出零及其所在下标

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

代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//未完待续
typedef int ElementType;
typedef struct Node *n;
struct Node{
    ElementType coef;
    ElementType expon;
    n next;
};
typedef n list;

list Read();    //读入数字
list Multiple(list L1, list L2);   //多项式乘积结果
list Sum(list L1, list L2);        //多项式和结果
void Print(list L);                //打印多项式
void Attach(int c, int e, n *p);    //尾插法
int Compare(int a, int b);          //比较数大

int main(){
    list L1,L2;
    list mul,sum;

    L1 = Read();
    L2 = Read();

    mul = Multiple(L1, L2);
    sum = Sum( L1, L2);
    Print(mul);
    Print(sum);

    return 0;
}


//尾插法函数!
void Attach(int c, int e, n *p){
    list L = (list)malloc(sizeof(struct Node));
    L->next = NULL;
    L->coef = c;
    L->expon = e;
    (*p)->next = L;
    *p = L;
}
/*
总结:
    函数内用*p(指针的指针)应该用括号!
    如(*P)->next
    尾插法不需要删除临时结点(即无临时结点)
    1.新建节点L,L->next 为空
    2.数据赋给新节点L
    3.*p(指针的指针)(尾结点指针的指针)
    新节点L 赋给*p(尾结点)的next节点——使链表连接
    4.新节点L 赋给*P(尾结点)代表新的尾结点
*/


list Read(){
    list p,s,t;//p是最后返回值,s是操作链
    int i;
    scanf("%d",&i);
    p = (list)malloc(sizeof(struct Node));//申请头结点
    p->next = NULL;     //头指针为空
    s = p;
    while(i--){
        int c, e;
        scanf("%d %d", &c, &e);
        Attach(c,e,&s);
    }

    t = p;
    p = p->next;
    free(t);

    return p;
}

/*
疑问:
    1.为什么list r = (list)malloc(sizeof(Node));
    中间直接填Node不行?而是要 Struct Node?

*/
/*
总结:
    运用尾插法进行读入操作
    1.新建节点P,此节点P作为临时表头(临时空节点)
        Note:赋值节点P next为空(指链表结束符
    2.将P赋给尾结点rear(防止丢失表头&紧跟表头插入元素
    3.N 需插入节点数
        当n不为0,读入节点数据,用Attach尾插插入元素
        n--
    4.删除临时生成的头结点
        list t;
        t = P; P = P->link; free(t);
        return P;
    Tips:
        1.while 和 i-- 同时需要时,可直接写作while(i--)
*/

list Multiple(list L1, list L2){
    list p,s;
    list a,b;
    int c,e;

    if(!L1 || !L2) return NULL;

    a = L1;
    b = L2;
    p = (list)malloc(sizeof(struct Node));
    p->next = NULL;
    s = p;//s表示尾结点
    
    while(b){       /*先用L1的第1项乘以L2,得到P*/
        Attach((a->coef * b->coef),(a->expon + b->expon),&s);
        b = b->next;
    }

    a = a->next;//L1的第二项
    while(a){//现在s链表中已经有上述的循环产生的链表了
        b = L2;
        s = p;
        while(b){
            c = a->coef * b->coef;//新节点的系数
            e = a->expon + b->expon;//新节点的指数
            
            /*判断s下一节点是否不为空 &&
            s下一节点的指数是否大于新节点的指数*/
            while(s->next && s->next->expon > e){
                s = s->next;    //s指向下一节点
            }
            
            /*下一节点指数相等*/
            if(s->next && s->next->expon == e){
                //要考虑系数相加是否为0的情况
                if(s->next->coef + c){
                    s->next->coef += c;
                }else{//链表下一节点的删除操作!
                    list t;
                    t = s->next;
                    s->next = t->next;
                    free(t);
                }
            }
            else if(c){/*下一节点指数小于新节点指数 或 下一节点空*/
                list t = (list)malloc(sizeof(struct Node));
                t->coef = c;
                t->expon = e;
                /*插入操作*/
                t->next = s->next;
                s->next = t;
                s = s->next;
            }

            b = b->next;
        }
        a = a->next;
    }
    //删头结点
    b = p;
    p = p->next;
    free(b);

    return p;
}
/*
总结:
    1.记得判空
    2.原理:先用链表1的第一项循环乘链表2的每一项,
    形成新链表p,然后再用表1乘表2的每一项判断插入
    3.用malloc函数新建为表头头结点空节点
    在最后应视情况删节点
    纠错
    4.应为b = b->next, 错写为a = a->next.
    5.与4错有关,ab和所代表的L1、L2弄错了
    6.e = a->expon + b->expon;//新节点的指数
    错写为
    e = a->expon + b->coef;//新节点的指数
    7.c = a->coef * b->coef;//新节点的系数
    错写为
    c = a->coef + b->coef;//新节点的系数
*/

list Sum(list L1, list L2){
    list p,s;//p返回值,s操作值
    list a,b;//a——L1,b——L2
    p = (list)malloc(sizeof(struct Node));
    p->next = NULL;
    s = p;

    if(!L1 && !L2){
        return NULL;
    }

    a = L1;
    b = L2;

    while(a && b){
        switch( Compare( a->expon, b->expon)){
            case 1:
                Attach(a->coef,a->expon,&s);
                a = a->next;
                break;
            case 0:
                if(a->coef + b->coef){
                    Attach(a->coef+b->coef,a->expon,&s);
                }
                a = a->next;
                b = b->next;
                break;
            case -1:
                Attach(b->coef,b->expon,&s);
                b = b->next;
                break;
        }
    }
    while(a){
        Attach(a->coef, a->expon, &s);
        a = a->next;

    }
    while(b){
        Attach(b->coef, b->expon, &s);
    }

    list t;
    t = p;
    p = p->next;
    free(t);

    return p;
    
}
/*
纠错:
    1.while(a)里应有a = a->next;(未加)
*/

void Print(list L){
    if(!L){
        printf("0 0");
        return;
    }
    printf("%d %d", L->coef, L->expon);
    L = L->next;
    while(L){
        printf(" %d %d", L->coef, L->expon);
        L = L->next;
    }
    printf("\n");
    return;
    
}
/*
纠错:
    1.printf("%d %d",&L->coef,&L->expon);
    会把L的地址打印出来,而不是打印需要的数字
*/

int Compare(int a, int b){
    int flag;
    if( a > b){
        flag = 1;
    }else if( a == b){
        flag = 0;
    }else {
        flag = -1;
    }
    return flag;
}
/*
纠错:
    1.else if(a == b) 错写为else if(a = b)
*/

总结

1.第一次自己写链表,好不容易写到几乎都正确了,只是最后一个样例“输入有零多项式和常数多项式”的结果是内存超限,不知道该怎么纠错,其他错点均在代码中每个函数下指出

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

代码

#include<stdio.h>
#include<stdlib.h>
#include<math.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];       //T1,T2已经在这里定义,视为全局变量

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

int main(){
    Tree R1,R2;

    R1 = BuildTree(T1);
    R2 = BuildTree(T2);

    if(Isomorphic(R1, R2)){
        printf("Yes");
    }else{
        printf("No");
    }

    return 0;
}

Tree BuildTree(struct TreeNode T[]){
    int N;
    int root = Null;
    int i;
    char cl, cr;
    
    scanf("%d\n",&N);   //重要改错节点!!
    int check[N];
    if(N){
        
        for( i=0; i<N; i++){    //初始化check数组
            check[i] = 0;
        }
        for( i=0; i<N; i++){    //读取树的数值,左右
            scanf("%c %c %c\n", &T[i].Element, &cl, &cr);
            if(cl != '-'){      //判断是否为空,存入数字,check判断
                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( i=0; i<N; i++){
            if(check[i] == 0){
                root = i;
                break;
            }
        }
    }
    
    return root;
}

/*
纠错:
    1.T[i].element/left/right 错写为 T.element/left/right
    2.int check[N] 未出错
    3.cl,cr应定义为char 错定义为int
    4.scanf("%d\n",&N); 
    写为 scanf("%d",&N); 时,仅两个样例正确,错误大多为段错误
    改正后仅一个样例错误
*/

int Isomorphic(Tree R1, Tree R2){
    if((R1 == Null) && (R2 == Null)){
        return 1;
    }else if(((R1 == Null) && (R2 != Null)) || ((R1 != Null) && (R2 == Null))){
        return 0;
    }else if( T1[R1].Element != T2[R2].Element){
        return 0;
    }else if((T1[R1].Left == Null) && (T2[R2].Left == Null)){
        return ( Isomorphic( T1[R1].right, T2[R2].right));
    }else 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));
    }
}

/*
纠错:
    1.T1[R1].Element != T2[R2].Element 错写为 R1 != R2
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值