PAT之静态链表

模板

(1)典型示例

输入:
(The address of a node is a 5-digit nonnegative integer, and NULL is represented by −1.)

  • the first line
    the address of the first node, and a positive N (≤ 1 0 5 10^5 105​​ ) which is the total number of nodes.
  • N lines
    Address Key Next
00100 5		
99999 -7 87654
23854 -15 00000
87654 15 -1
00000 -15 99999
00100 21 23854

即,00100 -> 23854 -> 00000 -> 99999 -> 87654 -> -1

(2)代码模板

#include<cstdio>

using namespace std;

const int N = 100000+10;    // 10^5

typedef struct{
    int adress;
    int data;
    int next;
    bool flag;      //是否是链表上的结点 (其它结点 = false)
    int order;      // 链表中结点的序号【从0开始】(其它结点 = N)
    /*  ... ...    */

}Node;

Node nodes[N];
int real_n=0;  //真正链表中的结点个数

int main(){
    // 初始化
    for(int i=0; i<N; i++){
        nodes[i].order = N;
    }
    // 输入
    int f_ad, n;
    scanf("%d%d", &f_ad, &n);
    int ad, data, next;
    for(int i=0; i<n; i++){
        scanf("%d%d%d", &ad, &data , &next);
        nodes[ad] = {ad, data, next};
    }
    // 设置flag order
    for(int i=f_ad; i!=-1; i=nodes[i].next){
        nodes[i].flag = true;
        nodes[i].order = real_n;
        real_n++;
    }
 	/*  ... ...    */
	// 输出
	printf("%05d %d %05d", nodes[i].adress, nodes[i].data, nodes[i].next);
    return 0;
}


1032(25:两个链表求公共结点)

(1)题目
两个链表求公共结点

代码:

#include<cstdio>

using namespace std;

const int N = 100000+10;

struct Node{
    char data;
    int next;
    bool flag;      // 是否是第一个链表中的元素
}nodes[N];

int main(){
    int ad1, ad2, n;
    scanf("%d %d %d", &ad1, &ad2, &n);
    int ad, next;
    char data;
    for(int i=0; i<n; i++){
        scanf("%d %c %d", &ad, &data, &next);
        nodes[ad] = {data, next, false};
    }
    // 遍历第一个链表
    for(int i=ad1; i!=-1; i=nodes[i].next){
        nodes[i].flag = true;
    }
    // 遍历第二个链表
    for(int i=ad2; i!=-1; i=nodes[i].next){
        if(nodes[i].flag){
            printf("%05d", i);
            return 0;
        }
    }
    printf("-1");
    return 0;
}

(3)小结

  • 全局变量的默认值
    int /int * /char /bool /double 默认值均是0
    char* /string 默认值为空(长度=0),char[i] 默认值是0
  • 链表结点:flag标志 很关键
  • struct 用{}赋值(struct没有构造函数)
    node[ad].data = data; node[ad].next = next; node[ad].flag = false;
    相当于
    nodes[ad] = {data, next, false};
  • 如何遍历一个链表
    for(int i=ad1; i!=-1; i=nodes[i].next){...}
  • 输出
    return 0 提前结束;
    最后输出 一般没有\n;

1052(25:链表排序)

(1)题目
链表排序

(2)代码

#include<cstdio>
#include<algorithm>

using namespace std;

const int N = 100000+10;

struct Node{
    int adress;
    int data;
    int next;
    bool flag;  //是否是链表的结点
}nodes[N];


// 前:flag=true, data小
bool cmp(Node no1, Node no2){
    if(no1.flag == no2.flag){
        return no1.data < no2.data;
    }else{
        return no1.flag > no2.flag;
    }
}

int main(){
    int ad, n;
    scanf("%d%d", &n, &ad);
    int ad2, data2, next2;
    for(int i=0; i<n; i++){
        scanf("%d%d%d", &ad2, &data2 , &next2);
        nodes[ad2] = {ad2, data2, next2, false};        // 所输入的结点不一定在链表中
    }
    int real_n = 0;     //真正链表中的结点个数
    // 遍历
    for(int i=ad; i!=-1; i=nodes[i].next){
        nodes[i].flag = true;
        real_n++;
    }
    // sort
    if(!real_n){
        printf("0 -1");
    }else{
        sort(nodes, nodes+N, cmp);
        printf("%d %05d\n", real_n, nodes[0].adress );		//不再是输入的ad
        for(int i=0; i<real_n; i++){
            printf("%05d %d ", nodes[i].adress, nodes[i].data);
            if(i!=real_n-1){
                printf("%05d\n", nodes[i+1].adress);
            }else{
                printf("-1");
            }
        }
    }

    return 0;
}

(3)小结

  • 审题:
    输入:where N is the total number of nodes in memory
    输出: where N is the total number of nodes in the list
  • 链表结点:
    flag 必有,因为(所输入的结点不一定在链表中, flag 和 real_n才是真的
    初始化:flag=false
    从队头遍历:flag=true
  • 链表排序
    链表结点:增加adress(不再以nodes[i]的下标为地址)
    先按 flag 排(flag=true在前), 再按 data 排(data小的在前)
    最后输出前n个结点
  • 边界: n=0

1074(25:链表反转(间隔k ))

(1)题目

链表反转(间隔k )

(2)代码

#include<cstdio>
#include<algorithm>

using namespace std;

const int N = 100000+10;

struct Node{
    int adress;
    int data;
    int next;
    bool flag;  //是否是链表的结点
    int order;   // 链表中结点的序号
}nodes[N];

// 前:flag=true, order小
bool cmp(Node no1, Node no2){
    if(no1.flag == no2.flag){
        return no1.order < no2.order;
    }{
        return no1.flag > no2.flag;
    }
}

void out_reverse(int start, int stop, int last){
    for(int i=stop; i>=start; i--){
        printf("%05d %d ", nodes[i].adress, nodes[i].data);
        if(i==start){
            if(last==-1){
                printf("-1");
            }else{
                printf("%05d\n", nodes[last].adress);
            }
        }else{
            printf("%05d\n", nodes[i-1].adress);
        }
    }
}

int main(){
    for(int i=0; i<N; i++){
        nodes[i].order = N;
    }
    int ad, n, k;
    scanf("%d%d%d", &ad, &n, &k);
    int ad2, data2, next2;
    for(int i=0; i<n; i++){
        scanf("%d%d%d", &ad2, &data2 , &next2);
        nodes[ad2] = {ad2, data2, next2, false};
    }
    int real_n = 0;     //真正链表中的结点个数
    // 遍历
    for(int i=ad; i!=-1; i=nodes[i].next){
        nodes[i].flag = true;
        nodes[i].order = real_n;
        real_n++;
    }
    // sort
    sort(nodes, nodes+N, cmp);
    int inter = real_n / k;
    if(real_n % k==0){
        // 正好分完
        for(int i=0; i<=inter-1; i++){
            if(i!=inter-1){
                out_reverse(i*k, i*k + k-1, (i+2)*k-1);
            }else{
                out_reverse(i*k, i*k + k-1, -1);
            }
        }
    }else{
        // 有剩下
        if(inter<1){
            for(int i=0; i<real_n; i++){
                printf("%05d %d ", nodes[i].adress, nodes[i].data);
                if(i==real_n-1){
                    printf("-1");
                }else{
                    printf("%05d\n", nodes[i+1].adress);
                }
            }
        }else{
            for(int i=0; i<=inter-1; i++){
                if(i!=inter-1){
                    out_reverse(i*k, i*k + k-1, (i+2)*k-1);
                }else{
                    out_reverse(i*k, i*k + k-1, (i+1)*k);
                }
            }
            for(int i=(inter-1)*k+k; i<real_n; i++){
                printf("%05d %d ", nodes[i].adress, nodes[i].data);
                if(i==real_n-1){
                    printf("-1");
                }else{
                    printf("%05d\n", nodes[i+1].adress);
                }
            }
        }
    }

    return 0;
}

(3)小结

  • 链表结点
    只要之后打乱结点,就要增加adress成员(如之后sort)
    与结点在链表中的序号有关,就要增加order成员
  • 测评:答案部分正确
    情况1:边界
    情况2:改写测试用例,测试各种情况的枝节

1097(25:删除链表上的重复数据)【非满分】

(1)题目

1097 删除链表上的重复数据

(2)代码

#include<cstdio>
#include<algorithm>

using namespace std;

const int N = 100000+10;

struct Node{
    int adress;
    int data;
    int next;
    int order;      //序号
    int keep;  //=0:在链表中,保留,=1:在链表中,移除,=N,不在链表中
}nodes[N];

int abso[N];  //绝对值=i, abso[i]=1,链表中已有

// 前:keep小,order小
bool cmp(Node no1, Node no2){
    if(no1.keep==no2.keep){
        return no1.order < no2.order;
    }else{
        return no1.keep < no2.keep;
    }
}

int main(){
    for(int i=0; i<N; i++){
        nodes[i].keep = N;
        nodes[i].order = N;
    }
    int ad, n;
    scanf("%d%d", &ad, &n);
    int ad2, data2, next2;
    for(int i=0; i<n; i++){
        scanf("%d%d%d", &ad2, &data2 , &next2);
        nodes[ad2] = {ad2, data2, next2};
    }
    int real_n = 0;     //真正链表中的结点个数
    // 遍历
    for(int i=ad; i!=-1; i=nodes[i].next){
        nodes[i].order = real_n;
        if(abso[abs(nodes[i].data)]==1){
            nodes[i].keep = 1;
        }else{
            abso[abs(nodes[i].data)]=1;
            nodes[i].keep = 0;
        }
        real_n++;
    }
    // remove
    sort(nodes, nodes+N, cmp);
    int remove_first=real_n;        // 第一个移除的结点序号
    for(int i=0; i<real_n; i++){
        if(nodes[i].keep==1){
            remove_first = i;
            break;
        }
    }
    for(int i=0; i<remove_first; i++){
        printf("%05d %d ", nodes[i].adress, nodes[i].data);
        if(i!=remove_first-1){
            printf("%05d\n", nodes[i+1].adress);
        }else{
            printf("-1\n");
        }
    }
    for(int i=remove_first; i<real_n; i++){
        printf("%05d %d ", nodes[i].adress, nodes[i].data);
        if(i!=real_n-1){
            printf("%05d\n", nodes[i+1].adress);
        }else{
            printf("-1\n");
        }
    }


    return 0;
}




(3) 小结

  • 静态链表的算法设计
    设计struct的成员,灵活结合sort()

1133(25:拆分链表)

(1)题目

拆分链表

(2)代码

#include<cstdio>
#include<algorithm>
#include<vector>

using namespace std;

const int N = 100000+10;    // 10^5

typedef struct{
    int adress;
    int data;
    int next;
    bool flag;      //是否是链表上的结点 (其它结点 = false)
    int order;      // 链表中结点的序号【从0开始】(其它结点 = N)
    /*  ... ...    */

}Node;

Node nodes[N];
int real_n=0;  //真正链表中的结点个数

bool cmp(Node node1, Node node2){
    return node1.order < node2.order;
}


int main(){
    // 初始化
    for(int i=0; i<N; i++){
        nodes[i].order = N;
    }
    // 输入
    int f_ad, n, k;
    scanf("%d%d%d", &f_ad, &n, &k);
    int ad, data, next;
    for(int i=0; i<n; i++){
        scanf("%d%d%d", &ad, &data , &next);
        nodes[ad] = {ad, data, next};
    }
    // 设置flag order
    for(int i=f_ad; i!=-1; i=nodes[i].next){
        nodes[i].flag = true;
        nodes[i].order = real_n;
        real_n++;
    }
 	/*  ... ...    */
    sort(nodes, nodes+N, cmp);
    vector<Node> vect;
    for(int i=0; i<real_n; i++){
        if(nodes[i].data<0){
            vect.push_back(nodes[i]);
        }
    }
    for(int i=0; i<real_n; i++){
        if(nodes[i].data>=0 && nodes[i].data<=k){
            vect.push_back(nodes[i]);
        }
    }
    for(int i=0; i<real_n; i++){
        if(nodes[i].data>k){
            vect.push_back(nodes[i]);
        }
    }
    for(int i=0; i<real_n; i++){
        if(i==real_n-1){
            vect[i].next = -1;
            printf("%05d %d %d", vect[i].adress, vect[i].data, vect[i].next);
        }else{
            vect[i].next = vect[i+1].adress;
            printf("%05d %d %05d\n", vect[i].adress, vect[i].data, vect[i].next);
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值