链式表的一些练习(第三周编程作业)

8 篇文章 0 订阅
2 篇文章 0 订阅

很少接触函数题,现在才发现,函数题比从零开始敲难多了。它能够把几乎所有的库限制住,还能限制参数,传给你什么参数你就必须用什么参数,诶嘛,我太难了。
所以,本九研究这五道题用了半个晚上加一个上午才搞明白。

第一题 小试牛刀,不成气候

本题要求实现一个函数,找到并返回链式表的第K个元素。

函数接口定义:

ElementType FindKth( List L, int K );

其中List结构定义如下:

typedef struct LNode *PtrToLNode;
struct LNode {
    ElementType Data;
    PtrToLNode Next;
};
typedef PtrToLNode List;

L是给定单链表,函数FindKth要返回链式表的第K个元素。如果该元素不存在,则返回ERROR。

裁判测试程序样例:

#include <stdio.h>
#include <stdlib.h>
#define ERROR -1
typedef int ElementType;
typedef struct LNode *PtrToLNode;
struct LNode {
    ElementType Data;
    PtrToLNode Next;
};
typedef PtrToLNode List;

List Read(); /* 细节在此不表 */

ElementType FindKth( List L, int K );

int main()
{
    int N, K;
    ElementType X;
    List L = Read();
    scanf("%d", &N);
    while ( N-- ) {
        scanf("%d", &K);
        X = FindKth(L, K);
        if ( X!= ERROR )
            printf("%d ", X);
        else
            printf("NA ");
    }
    return 0;
}

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

输入样例:
1 3 4 5 2 -1
6
3 6 1 5 4 2
输出样例:
4 NA 1 2 5 3

好久不用c了,现在对于c也只是配合一些cpp的使用,所以乍一读题,挺头疼的。而且我很受不了一下子那么多typedef,有点绕。阿不,太绕了!
这道题除了read()函数没写没办法编译之外,都还好,没啥可说的,直接粘代码吧。

ElementType FindKth( List L, int K )
{
    if(K<1)
    return ERROR;
    for(int i=1;i<K&&L!=NULL;i++)
    L = L->Next;
    if(L==NULL)
        return ERROR;
        else 
        return L->Data;
}

第二题 仍然无话可说

6-2 求单链表结点的阶乘和 (15 分)
本题要求实现一个函数,求单链表L结点的阶乘和。这里默认所有结点的值非负,且题目保证结果在int范围内。

函数接口定义:

int FactorialSum( List L );

其中单链表List的定义如下:

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

裁判测试程序样例:

#include <stdio.h>
#include <stdlib.h>
typedef struct Node *PtrToNode;
struct Node {
    int Data; /* 存储结点数据 */
    PtrToNode Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */

int FactorialSum( List L );

int main()
{
    int N, i;
    List L, p;

    scanf("%d", &N);
    L = NULL;
    for ( i=0; i<N; i++ ) {
        p = (List)malloc(sizeof(struct Node));
        scanf("%d", &p->Data);
        p->Next = L;  L = p;
    }
    printf("%d\n", FactorialSum(L));

    return 0;
}

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

输入样例:
3
5 3 6
输出样例:
846

对于这道题,需要注意的就是它读入的过程。因为对于本九的第一感觉,因为最后一次读入不涉及到next地址指向NULL操作,所以这道题目需要用N来控制循环。但又发现,函数没有传入N啊!
我靠,特喵的,要是从零编程,用N多特喵简单啊!!!
玄机在这里:

  L = NULL;
    for ( i=0; i<N; i++ ) {
        p = (List)malloc(sizeof(struct Node));
        scanf("%d", &p->Data);
        p->Next = L;  L = p;
    }

我们来看第一段循环,L=NULL,,p1被开辟出来,然后被装填数据,再然后,P1的next指向了L,也就是NULL,然后L指向了P1刚开辟的空间。这时候,作为第一个被存入的点P1,它的next是空的。
再来看第二段循环,又开了一个P2,P2被装填,P2的next指向了L,也就是p1,然后L指向了P2。
可知,L一直在指向最后一个,而最后一个的NEXT一直在指向前一个,所以说,p这个链表,是倒着被开辟出来的。头指针是L,然后最后一个节点的next就是NULL,所以不必担心,直接操作。
代码如下

//做一个阶乘的函数配合所编写的函数
int jiecheng(int n){
    int sum=1;
    if(n==0)return 1;
    for(int i=1;i<=n;i++)
    sum*=i;
    return sum;
}
int FactorialSum( List L ){
    int sum=0;
    while(L!=NULL){
        sum+=jiecheng(L->Data);
        L=L->Next;
    }
    return sum;
}

第三题 后边基础

6-3 建立学生信息链表 (20 分)
本题要求实现一个将输入的学生成绩组织成单向链表的简单函数。

函数接口定义:

void input();

该函数利用scanf从输入中获取学生的信息,并将其组织成单向链表。链表节点结构定义如下:

struct stud_node {
    int              num;      /*学号*/
    char             name[20]; /*姓名*/
    int              score;    /*成绩*/
    struct stud_node *next;    /*指向下个结点的指针*/
};

单向链表的头尾指针保存在全局变量head和tail中。

输入为若干个学生的信息(学号、姓名、成绩),当输入学号为0时结束。

裁判测试程序样例:

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

struct stud_node {
     int    num;
     char   name[20];
     int    score;
     struct stud_node *next;
};
struct stud_node *head, *tail;

void input();

int main()
{
    struct stud_node *p;
	
    head = tail = NULL;
    input();
    for ( p = head; p != NULL; p = p->next )
        printf("%d %s %d\n", p->num, p->name, p->score);

    return 0;
}

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

输入样例:
1 zhang 78
2 wang 80
3 li 75
4 zhao 85
0
输出样例:
1 zhang 78
2 wang 80
3 li 75
4 zhao 85

这道题目是后面两道题目的基础,昨天晚上把本九绕的哇,我靠。
一开始想用一个指针newone来做,后来发现,不大可能,因为next和newone总要和其他的节点关联,用一个很难实现。要不然,为啥第二题非得倒着存储呢?我不知道,但我目前没有设计出来一个正着存储而只需要一个指针的算法。
回头瞅了一眼题,哦,还有一个tail没有用,所以用上了这个tail,配合newone开辟空间,问题就迎刃而解啦~

本九给泥萌画一下吧
代码如下:

void input()
{
    struct stud_node *newone;
    newone=(struct stud_node *)malloc(sizeof(struct stud_node));
    scanf("%d", &newone->num);
    while(newone->num != 0)
    {
        scanf("%s %d", newone->name, &newone->score);
        if(head == NULL)//只在第一个节点的时候更新head
        {
             head = newone;
             head->next = NULL;
        }
       if(tail != NULL)//只在第一个节点的时候不更新tail
       {
           tail->next = newone;
       }
        tail = newone;
        tail->next = NULL;
        newone=(struct stud_node *)malloc(sizeof(struct stud_node));
        scanf("%d", &newone->num);
    }}

第四题 你比三题多一题~~~~~~~~~~~

本题要求实现两个函数,一个将输入的学生成绩组织成单向链表;另一个将成绩低于某分数线的学生结点从链表中删除。

函数接口定义:

struct stud_node *createlist();
struct stud_node *deletelist( struct stud_node *head, int min_score );

函数createlist利用scanf从输入中获取学生的信息,将其组织成单向链表,并返回链表头指针。链表节点结构定义如下:

struct stud_node {
    int              num;      /*学号*/
    char             name[20]; /*姓名*/
    int              score;    /*成绩*/
    struct stud_node *next;    /*指向下个结点的指针*/
};

输入为若干个学生的信息(学号、姓名、成绩),当输入学号为0时结束。

函数deletelist从以head为头指针的链表中删除成绩低于min_score的学生,并返回结果链表的头指针。

裁判测试程序样例:

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

struct stud_node {
     int    num;
     char   name[20];
     int    score;
     struct stud_node *next;
};

struct stud_node *createlist();
struct stud_node *deletelist( struct stud_node *head, int min_score );

int main()
{
    int min_score;
    struct stud_node *p, *head = NULL;

    head = createlist();
    scanf("%d", &min_score);
    head = deletelist(head, min_score);
    for ( p = head; p != NULL; p = p->next )
        printf("%d %s %d\n", p->num, p->name, p->score);

    return 0;
}

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

输入样例:
1 zhang 78
2 wang 80
3 li 75
4 zhao 85
0
80
输出样例:
2 wang 80
4 zhao 85

这个题就多了一个删除而已。因为第三题的读取和第四题的读取基本没差别,第四题就是比第三题多了重新申明头尾指针和返回一个头指针罢了。
而删除呢?
我是这个思路~
先创建一个p指针用来删除相应的下一个节点。
那么问题来了,如果第一个被删除呢?
所以我在走循环之前,先判断第一个能不能留下。如果能留下,在进入循环删除p的next指向的节点,如果不能留下,就一直找一直找,直到有一个节点留下为止。而如果没有头结点留下,那就是都删完了呗~直接返回NULL。
那么后面的找到不符合条件的,直接改next地址为它的下一个。如果符合条件,就只移动遍历指针p就行。所以需要一个删除没删除的bool变量deletesuccess=false。
但是!!!
c里面不能用bool变量吗?为啥给我报错!!???

fuck that damn it!!!

后来用的int型变量用1和0操纵的……(卑微)。
代码如下:

struct stud_node *createlist(){

    struct stud_node *newone,*head=NULL,*tail=NULL;
    newone=(struct stud_node *)malloc(sizeof(struct stud_node));
    scanf("%d", &newone->num);
    while(newone->num != 0)
    {
        scanf("%s %d", newone->name, &newone->score);
        if(head == NULL)
        {
             head = newone;
             head->next = NULL;
        }
       if(tail != NULL)
       {
           tail->next = newone;
       }
        tail = newone;
        tail->next = NULL;
        newone=(struct stud_node *)malloc(sizeof(struct stud_node));
        scanf("%d", &newone->num);
    }
    return head;
};



struct stud_node *deletelist( struct stud_node *head, int min_score )
{
    struct stud_node *p;
    int deletesuccess;
    p=head;
    if(head==NULL)return NULL;
    else if(head!=NULL){
        while(head->score<min_score){
            if(head->next==NULL)return NULL;
            else{
                head=head->next;
                p=head;}
        }
    }
    while(p->next!=NULL)
    {
        deletesuccess=0;
        if(p->next->score<min_score)
        {
            p->next=p->next->next;
           deletesuccess=1;
        }
        if(deletesuccess==0)
            p=p->next;
    }
    return head;
}

第五题 换汤不换药

6-5 删除单链表偶数节点 (20 分)
本题要求实现两个函数,分别将读入的数据存储为单链表、将链表中偶数值的结点删除。链表结点定义如下:

struct ListNode {
    int data;
    struct ListNode *next;
};

函数接口定义:

struct ListNode *createlist();
struct ListNode *deleteeven( struct ListNode *head );

函数createlist从标准输入读入一系列正整数,按照读入顺序建立单链表。当读到−1时表示输入结束,函数应返回指向单链表头结点的指针。

函数deleteeven将单链表head中偶数值的结点删除,返回结果链表的头指针。

裁判测试程序样例:

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

struct ListNode {
    int data;
    struct ListNode *next;
};
struct ListNode *createlist();
struct ListNode *deleteeven( struct ListNode *head );
void printlist( struct ListNode *head )
{
     struct ListNode *p = head;
     while (p) {
           printf("%d ", p->data);
           p = p->next;
     }
     printf("\n");
}

int main()
{
    struct ListNode *head;

    head = createlist();
    head = deleteeven(head);
    printlist(head);

    return 0;
}

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

输入样例:
1 2 2 3 4 5 6 7 -1
输出样例:
1 3 5 7

和第四题的差别就是少了俩数据元素,判断方式不一样了而已,就不多说了,会了第四题不会第五题,只能说明一个问题——

你根本不会第四题。

直接粘代码吧:

struct ListNode *createlist(){
    struct ListNode *newone,*head=NULL,*tail=NULL;
    newone=(struct ListNode*)malloc(sizeof(struct ListNode*));
    scanf("%d",&newone->data);
    while(newone->data!=-1){
        if(head==NULL){
            head=newone;
            head->next=NULL;
        }
        if(tail!=NULL){
            tail->next=newone;
        }
        tail=newone;
        tail->next=NULL;
         newone=(struct ListNode*)malloc(sizeof(struct ListNode*));
        scanf("%d",&newone->data);
    }
    return head;
};

struct ListNode *deleteeven( struct ListNode *head ){
    struct ListNode *p;
    int deletesuccess;
    p=head;
    if(head==NULL)return NULL;
    else if(head!=NULL){
        while(head->data%2==0){
            if(head->next!=NULL){
            head=head->next;
            p=head;}
            else return NULL;
        }
    }
    while(p->next!=NULL){
        deletesuccess=0;
        if(p->next->data%2==0){
            p->next=p->next->next;
            deletesuccess=1;
        }
        if(deletesuccess==0){
            p=p->next;
        }
    }
    return head;
};
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值