Educoder C&C++线性表实训

这篇具有很好参考价值的文章主要介绍了Educoder C&C++线性表实训。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

第1关:顺序构建线性表

第2关:逆序构建线性表

第3关:排序构建线性表

第4关:查找元素

第5关:删除指定位置的结点

第6关:删除包含特定数据的结点

第7关:线性表长度

第8关:线性表应用一:栈

第9关:线性表应用二:队列

第10关:线性表应用三:集合


第1关:顺序构建线性表

任务描述

本关任务:补全 insertHead函数 ,按照数据输入的顺序构建一个线性表。即如果输入的3个结点数据分别为1、2、3,则构建的线性表包含3个结点,且从前往后的结点数据分别为1、2、3

相关知识

线性表(linear list)是一种数据结构,是由 n 个具有相同特性的数据元素构成的序列。

线性表中元素的个数 n 即为线性表的长度,当 n = 0 时称为空表。线性表的相邻元素之间存在着序偶关系。

如用( a[0] ,…… ,a[i-1] ,a[i] ,a[i+1] ,…… ,a[n-1] )表示一个线性表,则称 a[i-1] 是 a[i] 的前驱,a[i+1] 是 a[i] 的后继

线性表的特性

  • 线性表中必存在唯一的一个“第一元素”;

  • 线性表中必存在唯一的一个“最后元素” ;

  • 除最后一个元素之外,均有唯一的后继;

  • 除第一个元素之外,均有唯一的前驱。

线性表的一般操作

  • 将线性表变为空表;

  • 返回线性表的长度,即表中元素个数;

  • 获取线性表某位置的元素;

  • 定位某个元素在线性表中的位置;

  • 在线性表中插入一个元素;

  • 删除某个元素;

  • 判断线性表是否为空;

  • 遍历输出线性表的所有元素;

  • 线性表排序。

线性表的表示方法

线性表可以用链表来实现。链表是通过指针链接在一起的一组数据项(结点)。

链表的每个结点都是同类型的结构,该结构中一般包含两类信息:

  • 数据域,存储业务相关的数据(如财务系统的数据域为财务信息,车辆管理系统的业务信息为车辆信息);

  • 指针域,用于构建结点的链接关系。单链表的实现只需要一个指针。

参考答案

#include "linearList.h"

node *insertTail(node *h, node *t)
{
    // 请在此添加代码,补全函数insertTail
    /********** Begin *********/
    if(h == NULL) // 空链表单独处理
    {
        t->next = NULL; // 链表尾指针置为NULL
        return t; // 返回第一个结点的地址(即链表头指针)
    }
    // 非空链表的情况
    node *p = h;
    // 让p指向最后一个结点
    while(p->next)
    {
        p = p->next;
    }
    p->next = t; // 让最后一个结点的指针域指向结点t
    t->next = NULL; // 链表尾指针置为NULL
    return h;  // 返回第一个结点的地址(即链表头指针)
    /********** End **********/
}

第2关:逆序构建线性表

任务描述

本关任务:补全 insertHead 函数,实现将一个结点插入到一个链表头部的功能。

相关知识

在介绍如何将一个结点插入到一个链表头部之前,我们先假设该链表头指针为 head,则 head 中存放着链表当前头结点的地址。

如果要将指针变量 t 指向的新结点插入到链表头部,其实只需要将原来的头结点的地址存入 t 指向结点的指针域(也就是让 t 指向结点的指针域指向原来的头结点),然后 t 指向的新结点就成了新的头结点了。那么,如何将原来的头结点的地址存入 t 指向结点的指针域?

t 指向结点的指针域可以用t->next访问,原来头结点的地址在 head 中,所以下面的语句可以实现这个功能:

t->next = head;

又由于新结点( t 指向的结点)是新的头结点,其地址必须存入头指针 head 中,而 t 指向结点的地址存放在指针变量 t 中,所以下面的语句可以实现这个功能:

head = t;

参考答案 

#include "linearList.h"

node * insertHead(node *h, node *t)
{
    // 请在此添加代码,补全函数insertHead
    /********** Begin *********/
    t->next = h;
    return t;
    /********** End **********/
}

第3关:排序构建线性表

任务描述

本关任务:补全 insertSort 函数,实现将一个结点按结点数据 data 从小到大的顺序插入到一个有序链表中。根据插入结点 data 的大小,插入点可能是链表头、尾或者中间某个位置。

相关知识

实现本关任务的关键分为两个步骤:

  • 一是找到插入点;

  • 二是插入结点。

参考答案

#include "linearList.h"

node * insertSort(node *h, node *t)
{
    // 请在此添加代码,补全函数insertSort
    /********** Begin *********/
    node *p = NULL, *q = h;  // 定位第一个插入点:链首
    // 查找插入点
    while(q && q->data < t->data)
    {// 两个指针并行后移
        p = q;
        q = q->next;
    }
    // 插入链首
    if(p == NULL)
    {
        t->next = h;
        return t;
    }
    // 插入链尾
    if(q == NULL)
    {
        p->next = t;
        t->next = NULL;
    }
    // 插入p、q之间
    t->next = q;
    p->next = t;
    return h;
    /********** End **********/
}

第4关:查找元素

任务描述

本关任务:补全 search 函数,实现在一个链表中搜索包含指定数据的结点。如果链表中有多个结点包含该数据,则返回第一个。

相关知识

遍历列表元素,在线性表中查找特定元素是线性表的常用操作之一。由于链表结点都是动态内存分配得到的,在内存中不是连续存储,没法使用二分法之类的算法来实现信息检索,但可以使用顺序查找的方法。顺序查找需要遍历整个链表,逐个检查每个结点是否满足条件。

参考答案

#include "linearList.h"

node * search(node * h, int num)
{
    // 请在此添加代码,补全函数search
    /********** Begin *********/
    while(h)
    {// h为真,即h指向的结点存在
        if(h->data == num)
        {
              return h;
        } 
        h = h->next;  // 将该结点的指针域赋值给h,h就指向了下一个结点
    }
    return NULL; // 没找到包含num的结点
    /********** End **********/
}

第5关:删除指定位置的结点

任务描述

本关任务:补全 delAt 函数,实现根据指定位置删除链表中对应的结点。

相关知识

删除链表结点

线性表的结点是有序号的,包含 n 个结点的线性表从链头到链尾的结点序号分别为0、1、…… 、n−1。删除线性表指定位置的操作也是常用的功能。

结点的删除可以根据结点位置的不同分为三种情况:删除链首结点、删除链尾结点、删除中间结点。

回答以下几个问题,解决本关问题就不难了:

  • 删除链首结点后,原来序号为1的结点成为新的链首结点,链表头指针也应该存储该结点的地址,该结点的地址原来存放在哪?

  • 删除链尾结点后,原来序号为n−2的结点成为新的链尾结点,该结点的指针域也应该置为“NULL”,表示链表的结束。怎么访问序号为n−2的结点的指针域?

  • 删除中间结点只需要将其前面结点的指针域修改为其后面结点的地址即可。例如删除序号为i的结点,需要将序号为i−1的结点的指针域修改为序号为i+1的结点地址。怎么访问序号为i−1的结点的指针域?序号为i+1的结点地址存放在哪?

参考答案

#include "linearList.h"

node * delAt(node * h, int i)
{
    // 请在此添加代码,补全函数delAt
    /********** Begin *********/
    // 序号非法,不删除
    if(i<0)
    {
        return h;
    }
    node *p = NULL, *q = h; // 定位删除结点,试图让q指向要删除结点,p指向其前面的结点
    for(int k = 0; k < i; k++)
    {
        if(q->next == NULL) // 后面没有结点了,序号非法
        {
            return h;
  	}
        p = q;
        q = q->next;
    }
    if(p) // p指向的结点存在,不是删除首结点
    {
        // 删除q指向的结点,让p指向结点的指针域指向q的后续结点
        p->next = q->next;
        // 释放空间
        delete q;
        return h;
    }
    else // 删除首结点
    {
        h = q->next; // 下一个结点成了首结点
        // 释放空间
        delete q;
        return h;
    }
    /********** End **********/
}

第6关:删除包含特定数据的结点

任务描述

本关任务:补全 delHas 函数,实现删除链表中包含特定数据的结点,如果有多个这样的结点,只删除第一个。

删除链表的结点时,有时候不知道结点在哪,只知道结点数据的特征,如删除成绩低于60的学生结点、删除学号为20160903的学生等。

参考答案

#include "linearList.h"

node * delHas(node * h, int n)
{
    // 请在此添加代码,补全函数delHas
    /********** Begin *********/
    // 序号非法,不删除
    node *p = NULL, *q = h;  // p为要删除结点的前结点,q指向要删除结点
    while(q)
    {// h为真,即h指向的结点存在
        if(q->data == n)
            break; // 找到了
        if(q->next == NULL)  // 后面没有结点了,没有结点满足条件
            return h;  // 不删除,直接返回
        // 继续往后找,两个指针一起后移
        p = q;
        q = q->next;
    }
    // 删除q指向的结点
    if(p == NULL)  // 删除头结点
    {
        h = q->next;  // 下一个结点变成头结点
        delete q;  // 删除结点
        return h;
    }
    // 不是头结点
    p->next = q->next;  // 把q指向结点的指针域(q后面结点的地址)赋值给p指向结点的指针域
    return h;
    /********** End **********/
}

第7关:线性表长度

任务描述

本关任务:编写 listLength 函数来求线性表的长度。

相关知识

为了完成本关任务,你只需遍历线性表,并逐个对结点计数即可。

参考答案

#include "linearList.h"

int listLength(node * h)
{
    // 请在此添加代码,补全函数listLength
    /********** Begin *********/
    int n = 0;
    while(h)
    {
        n++;
        h = h->next;
    }
    return n;
    /********** End **********/
}

第8关:线性表应用一:栈

任务描述

本关任务:用前面已经实现的线性表来实现一个整数栈(栈里的数据是整数)。共需要补全三个函数(也是栈的基本功能):判断栈空的 empty 函数、压栈的 push 函数和弹栈的 pop 函数。

相关知识

栈( stack )又名堆栈,是一种功能受限的线性表,具有先进后出的特性。

其限制为仅允许在线性表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底

  • 向一个栈插入新元素又称作进栈入栈压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;

  • 从一个栈删除元素又称作出栈弹栈退栈,它是把栈顶元素删除掉,使其下面的元素成为新的栈顶元素。

接下来首先声明结构类型:

// 定义结点结构
struct node
{
int data; // 数据域
node * next; // 指针域,指向下一个结点
};

typedef node * intStack; // 定义类型别名,intStack 即相当于 node*

定义 intStack 是为了使程序的可读性更好一些。因为本关是用线性表实现栈,而访问一个线性表其实只需要一个链表头指针就可以了,intStack 实际上就是node*类型,所以后面可以这样声明栈 sk 

intStack sk = NULL; // 声明栈 sk,并初始化为空栈(空线性表)

实际上 sk 就是一个node*类型的指针,用它可以访问一个线性表,也就可以看成一个栈了。

参考答案

#include "mstack.h"
// 函数empty:判断栈sk是否为空
// 参数:sk-栈
// 返回值:true-sk为空,false-sk不为空
bool empty(intStack sk)
{
    // 请在此添加代码,补全函数empty
    /********** Begin *********/
    return (listLength(sk) == 0);  // 链表长度为0,则栈为空
    /********** End **********/
}
// 函数pop:弹栈
// 参数:sk-栈,传引用,弹栈可能会改变sk的值
// 返回值:弹栈的弹出的整数,如果栈空,返回-1
int pop(intStack &sk)
{
    // 请在此添加代码,补全函数pop
    /********** Begin *********/
    if(empty(sk))  // 栈空,返回-1
        return -1;
    int n = sk->data;  // 获取栈顶结点(链首结点)的数据
    sk = delAt(sk,0);  // 删除首结点(弹栈,第一个结点出栈)
    return n;  // 返回弹栈数据
    /********** End **********/
}
// 函数push:压栈,将整数n压入栈sk中
// 参数:sk-栈,传引用,压栈会改变sk的值,n-要压栈的整数
// 返回值:无,采用链表实现栈,只要还有内存,压栈都会成功
void push(intStack &sk, int n)
{
    // 请在此添加代码,补全函数push
    /********** Begin *********/
    // 创建要压栈的结点
    node *p = new node;
    p->data = n;
    // 压栈(插入链首)
    sk = insertHead(sk,p);
    /********** End **********/
}

第9关:线性表应用二:队列

任务描述

本关任务:用前面已经实现的线性表来实现一个整数队列(队列里的数据是整数)。共需要补全三个函数(也是队列的基本功能):判断队列空的 queueEmpty 函数、入列的 enQueue 函数和出列的 deQueue 函数。

相关知识

队列是一种功能受限的线性表,具有先进先出的特性。队列仅允许从一头出列(这一头称为队列头),从另外一头入列(队列尾)。

  • 入列操作是将结点插入到队列尾(该结点称为新的队列尾);

  • 出列操作是从队列头删除头结点,并获取删除节点的数据(原头结点的后继结点为新的头结点)。

接下来首先声明结构类型:

// 定义结点结构
struct node
{
int data; // 数据域
node * next; // 指针域,指向下一个结点
};

typedef node * intQueue; // 定义类型别名,intQueue 即相当于 node*

定义 intQueue 是为了使程序的可读性更好一些。因为本关是用线性表实现队列,而访问一个线性表其实只需要一个链表头指针就可以了,intQueue 实际上就是node*类型,所以后面可以这样声明队列 iq 

intQueue iq = NULL; // 声明队列 iq,并初始化为空队列(空线性表)

实际上 iq 就是一个node*类型的指针,用它可以访问一个线性表,也就可以看成一个队列。

参考答案

#include "mqueue.h"

// 函数queueEmpty:判断队列iq是否为空
// 参数:iq-整数队列
// 返回值:true-队列iq为空,false-iq不为空
bool queueEmpty(intQueue iq)
{
    // 请在此添加代码,补全函数queueEmpty
    /********** Begin *********/ 
    return (iq==NULL);  // iq为NULL,则队列为空
    /********** End **********/
}
// 函数enQueue:将整数num入列到iq
// 参数:iq-整数队列,传引用,入列有可能改变队列头指针,num-入列的整数
// 返回值:无,只要还有内存,入列总会成功
void enQueue(intQueue &iq, int num)
{
    // 请在此添加代码,补全函数enQueue
    /********** Begin *********/
    // 准备结点
    node *t=new node;
    t->data=num;
    t->next=NULL;
    // 结点插入到尾部
    iq = insertTail(iq,t);
    /********** End **********/
}
// 函数deQueue:出列
// 参数:iq-整数队列,传引用,出列有可能改变队列头指针
// 返回值:出列结点的数据,如果队列为空,返回-1
int deQueue(intQueue &iq)
{
    // 请在此添加代码,补全函数deQueue
    /********** Begin *********/
    if(queueEmpty(iq))
        return -1;
    // 获取队列头结点的数据
    int n = iq->data;
    // 删除队列头结点(出列)
    iq = delAt(iq,0);
    // 返回出列数据
    return n;
    /********** End **********/
}

第10关:线性表应用三:集合

任务描述

本关任务:使用线性表实现集合的表示及操作。具体需要补全三个函数:计算集合并集的 unionSet 函数、计算集合交集的 intersection 函数和向集合中添加元素的 addElement 函数。

相关知识

集合

集合是数学中一个基本概念,它是集合论的研究对象。朴素集合论中,集合的定义就是“一堆东西”,集合里的“东西”,称为元素。

下面介绍几个集合的知识点:

  • 集合中的元素是无序的,对于任意的集合S1和S2,S1=S2当且仅当对于任意的对象a,都有若a∈S1,则a∈S2;若a∈S2,则a∈S1;

  • 集合中的元素互不相同,空集合是没有任何元素的集合;

  • 集合的并集定义为:A∪B=x∣x∈A或x∈B。例如,A={1,3,5},B={1,2,5} ,则A∪B= {1,2,3,5} ;

  • 集合的交集定义为:A∩B=x∣x∈A且x∈B。例如, A= {1,3,5},B={1,2,5} ,则A∩B= {1,5} 。

接下来首先声明结构类型:

// 定义结点结构
struct node
{
int data; // 数据域
node * next; // 指针域,指向下一个结点
};

typedef node * intSet; // 定义类型别名,intSet 即相当于 node*

上述结构类型的声明中定义 intSet 是为了使程序的可读性更好一些。因为本关是用线性表实现集合,而访问一个线性表其实只需要一个链表头指针就可以了, intSet 实际上就是node*类型,所以后面可以这样声明集合 a 

intSet a=NULL; // 声明集合 a,并初始化为空集合(空线性表)

参考答案 文章来源地址https://www.toymoban.com/news/detail-482821.html

#include "mset.h"

// 函数unionSet:求集合a和b的并集
// 参数:a-集合,b-集合
// 返回值:集合(集合a和b的并集)
intSet unionSet(intSet a, intSet b)
{
    // 请在此添加代码,补全函数unionSet
    /********** Begin *********/
    // 准备空集合
    intSet c=NULL;
    // 把a中每一个元素加入c中
    node *p=a;
    while(p)
    {
        addElement(c,p->data);
        p=p->next;
    }
    // 把b中每一个元素加入c中
    p=b;
    while(p)
    {
        addElement(c,p->data);
        p=p->next;
    }
    return c;
    /********** End **********/
}
// 函数intersection:求集合a和b的交集
// 参数:a-集合,b-集合
// 返回值:集合(集合a和b的交集)
intSet intersection(intSet a, intSet b)
{
    // 请在此添加代码,补全函数intersection
    /********** Begin *********/
    // 准备空集合
    intSet c=NULL;
    // 查看a中每一个元素
    node *p=a;
    while(p)
    {
        if(search(b,p->data))
        {// 也在b中,则选入集合c
            addElement(c,p->data);
        }
        p=p->next;
    }
    return c;
    /********** End **********/
}
// 函数addElement:在集合is中增加元素num
// 参数:is-集合,num-要增加的元素
// 返回值:无
void addElement(intSet &is, int num)
{
    // 请在此添加代码,补全函数addElement
    /********** Begin *********/
    // 首先确认num是否在is中
    node *p=search(is,num);
    if(p!=NULL)
        return;
    // 准备结点
    p=new node;
    p->data = num;
    p->next = NULL;
    is = insertHead(is,p);
    /********** End **********/
}

到了这里,关于Educoder C&C++线性表实训的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Educoder作业】C&C++函数实训

    是不是学会了函数就可以做任何题了… T1 登月纸桥 给出了函数的基本定义,可以在主函数上面定义函数,然后在主函数下面写函数。可能会显得可读性强一点? T2 几点几分了? 这里拆解进制的手段用的是之前博客里的拆解十进制的手段。最高位用下取整的除法,低位用取模

    2024年02月03日
    浏览(32)
  • 【Educoder作业】C&C++结构实训

    学好结构体是学好对象的基础。 T1 有理数化简 知道结构体是干嘛的就能做了,注意一些地方的特判即可。 T2 有理数加法 没啥区别啊感觉,注意求 g c d gcd g c d 别弄错了,实在不行咱就直接用 C + + C++ C + + 里自带的。 T3 有理数平均数 这个题我们处理好 g c d gcd g c d 的同时,搞

    2024年02月11日
    浏览(34)
  • 【Educoder作业】C&C++数组实训

    数组是很好用的。作为一个最基本的数据结构,数组是构成高级结构的基础。简单点的比如列表的next和head指针,桶的下标,栈;复杂点的比如说线段树的节点,KD树的平面,我们都需要数组进行实现。 T1 销售波动统计 这个题目显然是容易的,注意不要从 i = = 0 i==0 i = = 0 开始

    2024年02月05日
    浏览(33)
  • 【Educoder作业】C&C++指针实训

    不是很熟练,之前从来没用过,讲解不到位恕罪。 T1 去掉字符串首尾空格 我们需要知道两个事情,第一个事情是在函数中引用了数组指针之后,在函数内部就可以当做一个正常数组使用;第二个事情是字符串的末尾是用一个’\\0收尾的,所以我们在去掉末尾的空格时,在非空

    2024年02月09日
    浏览(45)
  • Educoder_头歌实训_离散数学_图论

    目录 第1关:图的概念 任务描述 相关知识 图的概念 习题参考 第2关:图的表示 任务描述 相关知识 图的表示 编程要求 测试说明 习题参考 第3关:单源最短通路问题 任务描述 相关知识 单源最短通路 Dijkstra算法 编程要求 测试说明 习题参考 本关任务:学习图的基本概念,完

    2024年02月03日
    浏览(34)
  • CSS--头歌(educoder)实训作业题目及答案

    目录 CSS——基础知识 第1关: 初识CSS:丰富多彩的网页样式 第2关: CSS样式引入方式 CSS——基础选择器 第1关: CSS 元素选择器 第2关: CSS 类选择器 第3关: CSS id选择器 CSS——文本与字体样式 第1关: 字体颜色、类型与大小 第2关: 字体粗细与风格 第3关: 文本装饰与文本布局 CSS——

    2024年04月15日
    浏览(92)
  • 【头歌educoder】离散数学实训参考-第一章-集合

    目录 1. 集合及其基本运算的实现 第一关:set简单应用 第二关:《仲夏夜之梦》中的回文单词对 第三关:求幂集  第四关:计算n个集合的笛卡尔乘积 2. 自然数系统 第一关:NaturalNumber的输出  第二关:NaturalNumber的加法 第三关:NaturalNumber的乘法 第四关:将NaturalNumber转换为阿

    2024年02月09日
    浏览(39)
  • JavaScript上部分--头歌(educoder)实训作业题目及答案

      目录 JS简介 第1关: JavaScript基础入门 第2关: JavaScript 与 HTML 第3关: JavaScript 变量 JS 数据类型 第1关: JavaScript 数据类型介绍 第2关: JavaScript 数据类型转换 JS运算符 第1关: 算术运算符 第2关: 比较和逻辑运算符 第3关: 条件和赋值运算符 第4关: 运算符的优先级和结合性 JS对象 第

    2024年02月08日
    浏览(27)
  • 【Educoder数据挖掘实训】插值填充法处理遗漏值

    开挖 这关的介绍非常详细,只要看懂了基本就没有问题。 所谓插值其实就是根据已有的数据构造出函数,然后用这个函数来计算遗漏的数据。 比如这个题目中介绍的拉格朗日插值以及 K K K 近邻。 有关拉格朗日插值在这里做一点儿介绍: 一直函数 f ( x ) f(x) f ( x ) 在 n + 1 n

    2024年03月12日
    浏览(73)
  • JavaScript下部分--头歌(educoder)实训作业题目及答案

    目录  JSON 第1关: JSON对象 第2关: JSON数组 第3关: JSON字符串 Math、日期和异常处理 第1关: Math类 第2关: Date类 第3关: JavaScript错误 HTML DOM——文档元素的操作(一) 第1关: 通过id获取文档元素 第2关: 通过类名获取文档元素 第3关: 通过标签名获取文档元素 第4关: html5中获取元素的

    2023年04月26日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包