【练习回顾】DS前三次作业

第一次作业

T2.基本计算器
使用了数组栈——数字栈和符号栈

T5.全排列输出(permutation)
使用了标准写法——字典序算法

void reverse(int left,int right);/*逆转a[left]~a[right]顺序*/
int nextPermutation(int n)/*1~n的全排列*/
{
    int i,j;
    for(i=n-1;i>0 && a[i]<a[i-1];i--); //从后向前,找到当前排列中首个a[i-1]<a[i](升序)的位置——即子列峰值
    if(i==0) return 0;
    else
    { //从a[i]开始向后,找到子排列中首个比a[i-1]小的a[j],这样a[j-1]就是最小的比a[i-1]大的数,是a[i-1]下一个全排列的目标值(我们就是这么想的)
      //于是交换a[i-1]和a[j-1]的值,再将其后的子列逆序以期得到极小的排列增长(其实就有递归的思想)
        for(j=i;j<n && a[j]>a[i-1];j++);
        a[j-1]^=a[i-1],a[i-1]^=a[j-1],a[j-1]^=a[i-1];
        reverse(i,n-1);
        return 1;
    }
}
/*主体操作,a[0]~a[n-1]全排列输出*/
    do{
        for(i=0;i<n;i++) printf("%d ",a[i]);
        puts("");               //输出
    }while(nextPermutation(n)); //得到下一个排列
    return 0;

e.g.
1  3  5  4  2
1  3  5  4  2  a[i-1]=3 从后向前首个升序处,也是下一个排列的目标更改出
1  3  5  4  2  a[j-1]=4 大于a[i-1]的极小值
1  4  5  3  2  此后子列必倒序逆序排列即可
1  4  2  3  5  < FINAL

第二次作业

选填
关于优先级:

[] , () , . , -> * , & ,++/--
从左向右 1 从右向左 2

一些可移植性差的函数警惕
feof() fflush()

第三次作业

T3.链表存储多项式时,野指针读入的错误及其衍生错误

typedef struct node
{
    int coef;
    int exp;
    struct node *link;
} PNode, *PLinklist; /*链表形式*/

PLinklist readPoly() /*读入多项式*/
{
    PLinklist list=NULL;
    //应为想用作接口,使用了局部的变量list来普遍化操作,结果忘记赋值成了野指针,在配合上本地CodeBlocks编译器的环境优化,产生了千奇百怪的错误结果
    PLinklist p,r;
    do
    {
        p=(PLinklist)malloc(sizeof(PNode));
        scanf("%d%d",&p->coef,&p->exp);
        p->link=NULL;
        if(list==NULL) list=p; //若为野指针,此处list==NULL就挂了
        else r->link=p;
        r=p;
    }while(getchar()!='\n');//当检测到行末'\n'后结束
    return list;
}

此次大失误让人进一步了解了自己编译器的尿性(猜测)
检测
咱的编译器会给野指针沿用之前历史的值,若没有历史则赋为NULL;
然后如果中间有些扰动(在其他域申明了相同名字的变量时)就会丢弃历史值。

因而两个链表连缀起来了

然而有些错误尚无法解释,需进一步研究:
image
加入printf("sf");后只读入前半,直接爆炸
加入printf("sf\n");就不会如此

T1.多线段连缀,找最长连续线段
由于数据点弱,感觉什么算法都能过,但自己竟然卡了那么久;
使用了自创的想法:单链表表示线段,单循环链表记录每条线段的头结点(方便顺次循环比较)
因为忽视了循环链表表头丢失的可能性

typedef struct node
{               /* 记录一条连续线段*/
    int x;
    int y;
    struct node *link;
} LNode, *Line;

typedef struct circleHead
{
    Line head;   /* 记录每个连续线段头结点*/
    int num;    /* 记录该连续线段的组成线段数*/
    struct circleHead *link;
} CNode, *hCoord;

int doConnect(int last) //还是无脑的循环比较,直至线段集合不再变动
{
    int i=0;
    hCoord p=Clist,q,pre;
    Line pp,rr;

    while(i<last)
    {
        pp=p->head;
        while(pp->link!=NULL) pp=pp->link;
        rr=pp;

        for(q=p->link,pre=p;q!=p;pre=q,q=q->link)
        {
            if(isConnect(q->head,rr))
            {
                rr->link=q->head->link;
                p->num+=q->num;
                pre->link=q->link;
                last--;
                i=0;//清零,否则会有跳过的可能性(好傻!)
                break;
            }
        }
        if(q==p) i++;
        else
        {
            free(q);
            continue;
        }
        p=p->link;
        Clist=p;     /* 注意当p不是Clist时,可能会因为Clist所指的结点移动到p结点后而导致Clist丢失*/
    }
    return last;
}

此题助教推荐了并查集,学学去

第三次作业的两个重大失误,源自于对链表指针的忽视,今后要特别注意

posted @ 2021-04-01 21:53  Xlucidator  阅读(67)  评论(0编辑  收藏  举报