PTA——21级数据结构与算法实验2——链表(参考答案)

7-1 单链表的创建及遍历

读入n值及n个整数,建立单链表并遍历输出。

输入格式:

读入n及n个整数。

输出格式:

输出n个整数,以空格分隔(最后一个数的后面没有空格)。

输入样例:

在这里给出一组输入。例如:

2
10 5

输出样例:

在这里给出相应的输出。例如:

10 5
#include<stdio.h>

#include<stdlib.h>

struct node

{

    int data;

    struct node *next;

};

struct node *creat(int n)

{

    int i;

    struct node *head,*p,*tail;

    head=(struct node*)malloc(sizeof(struct node));

    head->next=NULL;

    tail=head;

    for(i=0;i<n;i++)

    {

        p=(struct node*)malloc(sizeof(struct node));

        scanf("%d",&p->data);

        p->next=NULL;

        tail->next=p;

        tail=p;

    }

    return head;

}

void show(struct node *p)

{

    while(p)

    {

        if(p->next!=NULL)printf("%d ",p->data);

        else if(p->next==NULL)printf("%d\n",p->data);

        p=p->next;

    }

}

int main()

{

    int n;

    struct node *head;

    scanf("%d",&n);

    head=creat(n);

    show(head->next);

    return 0;

}

7-2 两个有序链表序列的合并

已知两个非降序链表序列S1与S2,设计函数构造出S1与S2合并后的新的非降序链表S3。

输入格式:

输入分两行,分别在每行给出由若干个正整数构成的非降序序列,用−1表示序列的结尾(−1不属于这个序列)。数字用空格间隔。

输出格式:

在一行中输出合并后新的非降序链表,数字间用空格分开,结尾不能有多余空格;若新链表为空,输出NULL

输入样例:

1 3 5 -1
2 4 6 8 10 -1

输出样例:

1 2 3 4 5 6 8 10
#include <stdio.h>

#include <stdlib.h>

#include <string.h>

typedef struct Node *Node;

struct Node

{

    int data;

    Node Next;

};

Node CList()

{

    int d;

    Node head = (Node)malloc(sizeof(struct Node)),q;

    head -> Next = NULL;

    q = head;

    while(~scanf("%d",&d)&&d!=-1)

    {

        Node p = (Node)malloc(sizeof(struct Node));

        p -> data = d;

        p -> Next = NULL;

        q -> Next = p;

        q = p;

    }

    return head;

}

Node Merge(Node a,Node b)

{

    a = a -> Next;

    b = b -> Next;

    Node head = (Node)malloc(sizeof(struct Node));

    head -> Next = NULL;

    Node q = head;

    while(a || b)

    {

        Node p = (Node)malloc(sizeof(struct Node));

        p -> Next = NULL;

        if(a == NULL || a -> data > b -> data)

        {

            p -> data = b -> data;

            b = b -> Next;

            q -> Next = p;

            q = p;

        }

        else

        {

            p -> data = a -> data;

            a = a -> Next;

            q -> Next = p;

            q = p;

        }

    }

    return head;

}

void printL(Node a)

{

    a = a -> Next;

    if(a == NULL)printf("NULL");

    int flag = 0;

    while(a)

    {

        if(flag)printf(" %d",a -> data);

        else printf("%d",a -> data);

        a = a -> Next;

        flag = 1;

    }

}

int main()

{

    Node a = CList();

    Node b = CList();

    Node c = Merge(a,b);

    printL(c);

}

7-3 两个有序链表序列的交集

已知两个非降序链表序列S1与S2,设计函数构造出S1与S2的交集新链表S3。

输入格式:

输入分两行,分别在每行给出由若干个正整数构成的非降序序列,用−1表示序列的结尾(−1不属于这个序列)。数字用空格间隔。

输出格式:

在一行中输出两个输入序列的交集序列,数字间用空格分开,结尾不能有多余空格;若新链表为空,输出NULL

输入样例:

1 2 5 -1
2 4 5 8 10 -1

输出样例:

2 5
#include <stdio.h>

#include <stdlib.h>

typedef struct node

{

int data;

struct node *next;

}node;

struct node *createList();

int main()

{

//尾插法创建链表

node *L1 = createList();

node *L2 = createList();

int cnt = 0,num = 0;//num统计交集个数

node *p1 = L1;

node *p2 = L2;

while(p1!=NULL&&p2!=NULL)

{

if(p1->data<p2->data)

{

p1 = p1->next;

}

else if(p1->data == p2->data)

{//cnt为了规范输出

num++;

if(cnt == 0)

{

cnt = 1;

printf("%d",p1->data);

}

else

{

printf(" %d",p1->data);

}

p1 = p1->next;

p2 = p2->next;

}

else

{

p2 = p2->next;

}

}

if(num==0)

printf("NULL");

return 0;

}

struct node *createList()

{

node *head = NULL;

head = (node*)malloc(sizeof(node));

head->next = NULL;

node *p = head;

int x;

scanf("%d",&x);

while(x!= -1)

{

node *q =NULL;

q = (node*)malloc(sizeof(node));

q->data = x;

p->next = q;

p = q;

q->next = NULL;

//q->next = NULL是必要的,否则最后会使q指针

//指向一个未知空间,导致程序错误

scanf("%d",&x);

}

return head->next;

}

7-4 约瑟夫环

N个人围成一圈顺序编号,从1号开始按1、2、3......顺序报数,报p者退出圈外,其余的人再从1、2、3开始报数,报p的人再退出圈外,以此类推。
请按退出顺序输出每个退出人的原序号。

输入格式:

输入只有一行,包括一个整数N(1<=N<=3000)及一个整数p(1<=p<=5000)。

输出格式:

按退出顺序输出每个退出人的原序号,数据间以一个空格分隔,但行尾无空格。

输入样例:

在这里给出一组输入。例如:

7 3

输出样例:

3 6 2 7 5 1 4
#include <stdio.h>

#include <stdlib.h>

struct node

{

    int data;

    struct node *next;

};

struct node *creat(int n)

{

    struct node *head,*p,*tail;

    int i;

    p=(struct node*)malloc(sizeof(struct node));

    p->data=1;

    p->next=NULL;

    head=tail=p;

    for(i=2;i<=n;i++)

    {

        p=(struct node*)malloc(sizeof(struct node));

        p->data=i;

        p->next=NULL;

        tail->next=p;

        tail=p;

    }

    tail->next=head;

    return (head);

}

int main()

{

    int n,m;

    struct node *head, *p,*q;

    scanf("%d %d",&n,&m);

    head=creat(n);

    q=head;

    while(q->next!=head)

    {

     q=q->next;

    }

     int con=0;

    while(q->next!=q)

     {

        p=q->next;

        con++;

        if(con==m)

        {

            printf("%d ",p->data);

            q->next=p->next;

            free(p);

            con=0;

        }

        else q=p;

    }

    printf("%d\n",q->data);

    return 0;

}

7-5 链表去重

给定一个带整数键值的链表 L,你需要把其中绝对值重复的键值结点删掉。即对每个键值 K,只有第一个绝对值等于 K 的结点被保留。同时,所有被删除的结点须被保存在另一个链表上。例如给定 L 为 21→-15→-15→-7→15,你需要输出去重后的链表 21→-15→-7,还有被删除的链表 -15→15。

输入格式:

输入在第一行给出 L 的第一个结点的地址和一个正整数 N(≤105,为结点总数)。一个结点的地址是非负的 5 位整数,空地址 NULL 用 -1 来表示。

随后 N 行,每行按以下格式描述一个结点:

地址 键值 下一个结点

其中地址是该结点的地址,键值是绝对值不超过104的整数,下一个结点是下个结点的地址。

输出格式:

首先输出去重后的链表,然后输出被删除的链表。每个结点占一行,按输入的格式输出。

输入样例:

00100 5
99999 -7 87654
23854 -15 00000
87654 15 -1
00000 -15 99999
00100 21 23854

输出样例:

00100 21 23854
23854 -15 99999
99999 -7 -1
00000 -15 87654
87654 15 -1
#include<stdio.h>

#include<string.h>

#include<math.h>

#include<malloc.h>

#define N 100010

struct LNode {

    int idex;//该节点的地址

    int data;//该节点的数据

    int nextidex;//下个节点的地址

    struct LNode* next;

};

typedef struct LNode* List;

int main()

{

    int a[N] = { 0 };//记录地址的data

    int b[N] = { 0 };//记录重复

    int c[N] = { 0 };//记录下一个地址

    int n;//做循环

    int m;//表头

    int zb;//给b数组做定位

    int cb;//给a数组做定位

    int sb;//存data的

    scanf("%d %d", &m, &n);

    int i = 0;

    for (i = 0; i < n; i++) {

        scanf("%d %d %d", &zb, &sb, &cb);

        a[zb] = sb;

        c[zb] = cb;

        //    b[abs(sb)]++;

    }

    if (n == 1) {

        printf("%05d %d -1", zb, sb);

        return 0;

    }

    if (n == 0) {

        return 0;

    }

    int aim = m;

    List head, tail, p1, tou, wei;

    //head为去重后的链表,tou为有重复的数字链表

    //tail为去重后链表的尾指针,wei为有重复的数字的链表的尾指针

    head = tail = p1 = tou = wei = NULL;

    for (aim = m; aim != -1; aim = c[aim]) {

        p1 = (List)malloc(sizeof(struct LNode));

        p1->idex = aim;

        p1->data = a[aim];

        p1->nextidex = c[aim];//将该节点的内容扣在结构体上

        if (b[abs(p1->data)]) {

            if (tou == NULL) {

                tou = p1;

            }

            else {

                wei->next = p1;

                wei->nextidex=p1->idex;

            }

            wei = p1;

        }

        else {

            b[abs(p1->data)]++;

            if (head == NULL) {

                head = p1;

            }

            else {

                tail->next = p1;

                tail->nextidex=p1->idex;

            }

            tail = p1;

        }

    }

    List L, l;

    L = head;

    l = L->next;

    while (l) {//输出无重复的链表

        printf("%05d %d %05d\n", L->idex, L->data, L->nextidex);

        L = l;

        l = l->next;

    }

    printf("%05d %d -1\n", L->idex, L->data);

    L=tou;

    l=L->next;

    if (tou) {//输出重复的数字链表

        while (l) {

            printf("%05d %d %05d\n", L->idex, L->data, L->nextidex);

            L = l;

            l = l->next;

        }

        printf("%05d %d -1\n", L->idex, L->data);

    }

}

7-6 带头节点的双向循环链表操作

本题目要求读入一系列整数,依次插入到双向循环链表的头部和尾部,然后顺序和逆序输出链表。

链表节点类型可以定义为

typedef int DataType;
typedef struct LinkedNode{
    DataType data;
    struct LinkedNode *prev;
    struct LinkedNode *next;
}LinkedNode;

链表类型可以定义为

typedef struct LinkedList{
  int length; /* 链表的长度 */
  LinkedNode head; /* 双向循环链表的头节点 */
}LinkedList;

初始化链表的函数可声明为

void init_list(LinkedList *list);

分配节点的函数可声明为

LinkedNode *alloc_node(DataType data);

头部插入的函数可声明为

void push_front(LinkedList *list, DataType data);

尾部插入的函数可声明为

void push_back(LinkedList *list, DataType data);

顺序遍历的函数可声明为

void traverse(LinkedList *list);

逆序遍历的函数可声明为

void traverse_back(LinkedList *list);

输入格式:

输入一行整数(空格分隔),以-1结束。

输出格式:

第一行输出链表顺序遍历的结果,第二行输出逆序遍历的结果。

输入样例:

在这里给出一组输入。例如:

1 2 3 4 5 6 -1

输出样例:

5 3 1 2 4 6
6 4 2 1 3 5
#include<iostream>

using namespace std;

typedef int DataType;

typedef struct LinkedNode {

    DataType data;

    struct LinkedNode* prev;

    struct LinkedNode* next;

}LinkedNode;

typedef struct LinkedList {

    int length; /* 链表的长度 */

    LinkedNode* head; /* 双向循环链表的头节点 */

}LinkedList;

void init_list(LinkedList* list)//初始化链表

{

    list->length = 0;

    list->head = new LinkedNode;

    list->head->next = list->head;

    list->head->prev = list->head;

}

LinkedNode* alloc_node(DataType d)//给节点分配内存空间

{

    LinkedNode* L;

    L = new LinkedNode;

    L->data = d;

    L->prev = NULL; L->next = NULL;

    return L;

}

void push_front(LinkedList* list, DataType data)//头插法

{

    LinkedNode* cur = alloc_node(data);

    //当链表只有头结点时

    if (list->head->next == list->head) {

        list->head->next = cur;

        cur->next = list->head;

        cur->prev = list->head;

        list->head->prev = cur;

    }

    else {

        cur->next = list->head->next;//将新节点的next域指向原链表中头结点后面的节点

        list->head->next->prev = cur;//然后将原头结点中后面节点prev域指向新节点;

        cur->prev = list->head;//将新节点prev域指向头结点

        list->head->next = cur;//将头结点的next域指向新节点

    }list->length++;

}

void push_back(LinkedList* list, DataType data)//尾插法

{

    LinkedNode* cur = NULL;

    //如果链表内只有头结点

    if (list->head->next == list->head) {

        cur = alloc_node(data);

        list->head->next = cur;

        cur->prev = list->head;

        cur->next = list->head;

        list->head->prev = cur;

    }//如果链表内有其他节点

    else {

        cur = alloc_node(data);

        list->head->prev->next = cur;

        cur->prev = list->head->prev;

        list->head->prev = cur;

        cur->next = list->head;

    }list->length++;

}

void traverse(LinkedList* list)//顺序遍历

{

    LinkedNode* cur = list->head->next;

    //如果链表为空

    if (list->length == 0) {}//啥也不用干

    else {

        for (int i = 0; i < list->length; i++) {

            if( i != list->length-1)cout << cur->data << " ";

            else cout << cur->data;

            cur = cur->next;

        }   cout << endl;

    }

}

void traverse_back(LinkedList* list)//倒序遍历

{

    LinkedNode* cur = list->head->prev;

    //如果链表为空

    if (list->length == 0) {}

    else {

        for (int i = 0; i < list->length; i++) {

            if( i != list->length-1)cout << cur->data << " ";

            else cout << cur->data;

            cur = cur->prev;

        }cout << endl;

    }

}

//自己增加的内容 销毁双向循环链表

void destroy(LinkedList* list)

{

    LinkedNode* cur = list->head->next;

    while (cur != list->head) {

        LinkedNode* ret = cur;

        cur = cur->next;

        delete ret;

    }delete(list->head);

}

int main() {

    int data;

    LinkedList L,*pHead=&L;

    init_list(pHead);

    int flag = 1;//根据输出结果可以观察得到构建链表时头插一次,尾插一次,以此类推

    cin >> data;

    while (data != -1)

    {

        if (flag)

        {

            push_front(pHead, data);

            flag = 0;

        }

        else

        {

            push_back(pHead, data);

            flag = 1;

        }

        cin >> data;

    }

    traverse(pHead);

    traverse_back(pHead);

    destroy(pHead);//销毁链表

    return 0;

}

7-7 单链表就地逆置

输入多个整数,以-1作为结束标志,顺序建立一个带头结点的单链表,之后对该单链表进行就地逆置(不增加新结点),并输出逆置后的单链表数据。

输入格式:

首先输入一个正整数T,表示测试数据的组数,然后是T组测试数据。每组测试输入多个整数,以-1作为该组测试的结束(-1不处理)。

输出格式:

对于每组测试,输出逆置后的单链表数据(数据之间留一个空格)。

输入样例:

1
1 2 3 4 5 -1

输出样例:

5 4 3 2 1
#include<stdio.h>

#include <stdlib.h>

struct node

{

    int data;

    struct node *next;

};

struct node *creat()

{

    struct node *head,*p,*tail;

    int x;

    head=(struct node*)malloc(sizeof(struct node));

    head->next=NULL;

    tail=head;

    while(scanf("%d",&x)&&x!=-1)

    {

        p=(struct node*)malloc(sizeof(struct node));

        p->data=x;

        p->next=NULL;

        tail->next=p;

        tail=p;

    }

    return (head);

}

void reverse(struct node *head)

{

    struct node *p,*q;

    p=head->next;

    head->next=NULL;

    q=p->next;

    while(p!=NULL)

    {

        p->next=head->next;

        head->next=p;

        p=q;

        if(q!=NULL)

        {

            q=q->next;

        }

    }

}

int main()

{

    int T;

    scanf("%d",&T);

    while(T--)

    {

    struct node *head,*p;

    head=creat();

    reverse(head);

    p=head->next;

    while(p)

    {

        if(p->next==NULL)printf("%d\n",p->data);

        else printf("%d ",p->data);

        p=p->next;

    }  

    }

    return 0;

}

7-8 重排链表

给定一个单链表 L1​→L2​→⋯→Ln−1​→Ln​,请编写程序将链表重新排列为 Ln​→L1​→Ln−1​→L2​→⋯。例如:给定L为1→2→3→4→5→6,则输出应该为6→1→5→2→4→3。

输入格式:

每个输入包含1个测试用例。每个测试用例第1行给出第1个结点的地址和结点总个数,即正整数N (≤105)。结点的地址是5位非负整数,NULL地址用−1表示。

接下来有N行,每行格式为:

Address Data Next

其中Address是结点地址;Data是该结点保存的数据,为不超过105的正整数;Next是下一结点的地址。题目保证给出的链表上至少有两个结点。

输出格式:

对每个测试用例,顺序输出重排后的结果链表,其上每个结点占一行,格式与输入相同。

输入样例:

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

输出样例:

68237 6 00100
00100 1 99999
99999 5 12309
12309 2 00000
00000 4 33218
33218 3 -1
#include <cstdio>

#include <iostream>

#include <algorithm>

using namespace std;



typedef struct point {

    int next;

    int data;

}point;



point p[1000002];//储存输入时的顺序

int a[1000002]; //储存链表顺序(只记录地址)

int b[1000002]; //排好后的顺序

int main() {

    int n, begin,address;

    cin >> begin >> n;

    for (int i = 0; i < n; i++) {

        cin >> address;

        cin >> p[address].data >> p[address].next; //p现在储存的输入顺序

    }

    int h = 0;

    while (begin != -1) {

        a[h] = begin;

        h++;

        begin = p[begin].next;

    }  // a现在是链表状态

    //别用n,用计数器h,n不一定是结点个数

    int i = 0, j = h - 1,k=0;//双指针

    for (int t = 0; t < h; t++) {

        if (t % 2 == 0) {  

            b[k] = a[j];

            k++;

            j--;

        }

        else {

            b[k] = a[i];

            k++;

            i++;

        }

    }

    for (int i = 0; i < k-1; i++) {

        printf("%05d %d %05d\n", b[i], p[b[i]].data, b[i+1]);

    }

    printf("%05d %d -1", b[k - 1], p[b[k-1]].data);

}//最后一个格式不一样,单独处理

7-9 头插法创建单链表、遍历链表、删除链表

#include<stdio.h>

#include <stdlib.h>

struct node

{

    int data;

    struct node *next;

};

struct node *creat( )

{

 struct node *head,*p;

 int a;

 head=(struct node*)malloc(sizeof(struct node));

 head->next=NULL;

 while(scanf("%d",&a)&&a!=-1)

 {

     p=(struct node*)malloc(sizeof(struct node));

     p->data=a;

     p->next=head->next;

     head->next=p;

 }

 return head;

}

void DeleteLink(struct node *head)

{

    struct node *p;

    while(head->next)

    {

        p=head->next;

        head->next=p->next;

        free(p);

    }

}

int main()

{

    struct node *head,*p;

    int k;

    scanf("%d",&k);

    while(k--){

    head=creat();

    p=head->next;

    while(p)

    {

        if(p->next==NULL)printf("%d ",p->data);

        else printf("%d ",p->data);

        p=p->next;

    }

    printf("\n");

    DeleteLink(head);

    }

    return 0;

}

7-9 头插法创建单链表、遍历链表、删除链表

输入一系列自然数(0和正整数),输入-1时表示输入结束。按照输入的顺序,用头插法建立单链表,并遍历所建立的单链表,输出这些数据。注意 -1 不加入链表。

输入格式:

第一行是一个正整数k,表示以下会有k组测试数据。

每组测试数据是一系列以空格隔开的自然数(0和正整数)。数列末尾的 -1 表示本组测试数据结束。按照输入的顺序,用头插法建立单链表,并遍历所建立的单链表,输出这些数据。注意 -1 不加入链表。

输出格式:

对于每组测试数据,输出链表中各节点的数据域。每个数据后有一个空格。每组测试数据的输出占1行。

输入样例:

3
1 2 3 4 5 -1 
30 20 10 -1 
4 2 2 1 1 2 0 2 -1 

输出样例:

在这里给出相应的输出。例如:

5 4 3 2 1 
10 20 30 
2 0 2 1 1 2 2 4 

注意:对每组测试数据,创建链表,遍历链表输出之后,一定要删除链表,否则会出现“内存超限”。

#include<stdio.h>
#include <stdlib.h>
struct node
{
    int data;
    struct node *next;
};
struct node *creat( )
{
 struct node *head,*p;
 int a;
 head=(struct node*)malloc(sizeof(struct node));
 head->next=NULL;
 while(scanf("%d",&a)&&a!=-1)
 {
     p=(struct node*)malloc(sizeof(struct node));
     p->data=a;
     p->next=head->next;
     head->next=p;
 }
 return head;
}
void DeleteLink(struct node *head)
{
    struct node *p;
    while(head->next)
    {
        p=head->next;
        head->next=p->next;
        free(p);
    }
}
int main()
{
    struct node *head,*p;
    int k;
    scanf("%d",&k);
    while(k--){
    head=creat();
    p=head->next;
    while(p)
    {
        if(p->next==NULL)printf("%d ",p->data);
        else printf("%d ",p->data);
        p=p->next;
    }
    printf("\n");
    DeleteLink(head);
    }
    return 0;
}

  • 9
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

救救孩子√

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值