1. 设计思路

本项目的实质是完成对考生信息的建立、查找、插入、修改、删除等功能,可以首先定义项目的数据结构,然后将每个功能写成一个函数来完成对数据的操作,最后完成主函数以验证各个函数功能并得出运行结果。

2. 数据结构

本项目的数据是一组考生信息,每条考生信息由准考证号、姓名、性别、年龄、报考类别等信息组成,这组考生信息具有相同特性,属于同一数据对象,相邻数据元素之间存在序偶关系。由此可以看出,这些数据也具有线性表中数据元素的性质,所以该系统的数据可以采用线性表来存储。

从上一节的例子中可见,线性表的顺序存储结构的特点是逻辑关系相邻的两个元素在物理位置上也相邻,因此可以随机存储表中任一元素,它的存储位置可用一个简单、直观的公式来表示。然而,从另一个方面来看,这个特点也铸成了这种存储结构的弱点:在做插入或删除操作时,需要移动大量元素。

为克服这一缺点,我们引入另一种存储形式――链式存储。链式存储是线性表的另一种表示方法,由于它不要求逻辑上相邻的元素在物理位置上也相邻,因此它没有顺序存储结构的弱点,但同时也失去了顺序表可随机存取的特点。

链式存储的优点是插入或删除元素时很方便,使用灵活。缺点是存储密度小,存储空间利用率低。事实上,链表插入、删除运算的快捷是以空间代价来换取时间。

顺序表适宜于做查找这样的静态操作;链表宜于做插入、删除这样的动态操作。

  • 若线性表的长度变化不大,且其主要操作是查找,则采用顺序表;
  • 若线性表的长度变化较大,且其主要操作是插入、删除操作,则采用链表;

本项目主要进行插入、删除、修改等操作,所以采用链式存储结构比较适合。用结构体类型定义每个考生信息,故该单链表中的每个结点的结构可描述为:

// 单链表中单个结点的完整数据结构定义
typedef struct LNodeTag
{Student stu;    // 值域LNodeTag *next;    // 指针域
}LNode;

假设 LLNode* 型变量,L为单链表的头指针,它指向表中的第一个结点。若 L 为空 L=NULL,则表示的线性表为空表,其长度 n 为 0。

有时我们在单链表的第一个结点之前设置一个结点,称之为头结点,头结点的数据域可以不存储任何信息,也可以存储线性表的长度等类附加信息,头结点的指针域存储指向第一个结点的指针(即第一个元素结点的存储位置),如图 2.7a 所示,此时单链表的头指针指向头结点。

若线性表为空表,则头结点的指针域为空,如图 2.7b 所示。


根据这里的分析不难发现,链表在新增、删除数据都比较容易,可以在 O(1) 的时间复杂度内完成。但对于查找,不管是按照位置的查找还是按照数值条件的查找,都需要对全部数据进行遍历。这显然就是 O(n) 的时间复杂度。

虽然链表在新增和删除数据上有优势,但仔细思考就会发现,这个优势并不实用。这主要是因为,在新增数据时,通常会伴随一个查找的动作。例如,在第五个结点后,新增一个新的数据结点,那么执行的操作就包含两个步骤:

  • 查找第五个结点;

  • 再新增一个数据结点;

整体的复杂度就是 O(n) + O(1)

2.1 创建空链表

使用下面代码创建一个仅有头结点的单链表(空单链表)

LinkList::LinkList()
{head = new LNode;   // 产生头结点,并使 head 头指针 指向此头结点head->next = NULL;  // 指针域为空std::cout << "constructor done" << std::endl;
}

创建结果见下图

2.2 销毁链表

销毁单链表

LinkList::~LinkList()
{LNode *q;while (head){q = head->next;delete head;head = q;}std::cout << "destructor done" << std::endl;
}

销毁结果见下图:

2.3 插入元素


要在第 i 个位置插入一个新的结点, 则需要先找到第 i-1 个结点,如下图

2.4 删除结点


同样要在第 i 个位置删除一个结点, 则需要先找到第 i-1 个结点,如下图

3. 程序清单

project.h

#include <iostream>
#include <string>// 单链表中结点的值域数据结构定义
typedef struct StudentTag
{std::string id;std::string name;std::string gender;int age;// 结构体初始化StudentTag(std::string i="", std::string n="", std::string g="", int a=0) {id = i;name = n;gender = g;age = a;}
}Student;// 单链表中单个结点的完整数据结构定义
typedef struct LNode
{Student stu;    // 值域LNode *next;    // 指针域
}LNode;class LinkList
{public:LinkList();~LinkList();void init_list();void clear_list();bool is_empty();int print_list();int get_list_length();int get_element(int i, Student &data);  //  返回单链表中指定序号的结点值bool search_element(Student data);       //  从单链表中查找元素int insert_element(int i, const Student data);int delete_element(int i, Student &data);int update_element(const Student data);private:LNode *head;
};

project.cpp

#include "project.h"LinkList::LinkList()
{head = new LNode;   // 产生头结点,并使 head 指向此头结点head->next = NULL;  // 指针域为空std::cout << "constructor done" << std::endl;
}LinkList::~LinkList()
{LNode *q;while (head){q = head->next;delete head;head = q;}std::cout << "destructor done" << std::endl;
}void LinkList::clear_list()
{std::cout << "clear_list start" << std::endl;LNode *q;LNode *p = head->next;  // p 指向第一个结点while (p)   // 循环到表尾{q = p->next;delete p;p = q;}head->next = NULL;  // 头结点指针域为空std::cout << "clear_list done" << std::endl;
}bool LinkList::is_empty()
{if(head->next){return false;}else{return true;}// return head->next ? false : true;
}int LinkList::print_list()
{LNode *p = head->next;int length = get_list_length();if(length == 0){std::cout << "list length is 0" << std::endl; return 0;}while (p){std::cout   << "id:" << p->stu.id << " "<< "name:" << p->stu.name << " "<< "age:" << p->stu.age << " "<< "gender:" << p->stu.gender << " "<< std::endl;p = p->next;}return 0;
}int LinkList::get_list_length()
{int length = 0;LNode *p = head->next;while (p){   length += 1;p = p->next;}return length;
}int LinkList::get_element(int i, Student &data)
{int k = 1;LNode *p = head->next;while (p){   if(k++ == i){data = p->stu;return 0;}p = p->next;}return 1;// 如果函数返回的是获取到的结构体值,则使用 return head->data;
}bool LinkList::search_element(Student data)
{LNode *p = head->next;while (p){   // 只要学生的学号相等就认为这两个结构体相等if(data.id == p->stu.id){return true;}p = p->next;}return false;
}int LinkList::insert_element(int i, Student data)
{int k = 1;// 找到要插入的第 i 个元素的前一个位置,并让 p 指向该结点LNode *p = head;while(p->next && k < i)   {p = p->next;k++;}// 新建一个结点用于存储要输入的数据 dataLNode *q = new LNode;q->stu = data;q->next = NULL;// 将新数据插入到链表中 q->next = p->next;p->next = q;return 0;
}int LinkList::delete_element(int i, Student &data)
{int k = 1;int length = get_list_length();if(is_empty() || i < 1 || i > length){std::cout << "要删除的元素位置不合理" << std::endl;return -1;}// 找到要删除的第 i 个元素的前一个位置,并让 p 指向该结点LNode *p = head;while(p->next && k < i)   {p = p->next;k++;}if(!(p->next) || k > i){return -1;}// 将要删除的数据赋值给 data/*data = p->next->stu;// 删除对应的结点delete p->next;p->next = p->next->next;return 0;*/LNode *q;q = p->next;data = q->stu;// 删除对应的结点delete p->next;p->next = q->next;return 0;
}int LinkList::update_element(Student data)
{// 找到要更新的元素,假设要修改数据的 data.id 与链表中的 p->stu.id 相等LNode *p = head;while(p->next)   {p = p->next;if(p->stu.id == data.id){p->stu.name = data.name;p->stu.age = data.age;p->stu.gender = data.gender;}}return 0;
}

main.cpp

#include "project.cpp"int main()
{LinkList L;Student sa("001", "A", "male", 18);L.insert_element(1, sa);Student sb("002", "B", "male", 19);L.insert_element(2, sb);Student sc("003", "C", "male", 20);L.insert_element(3, sc);std::cout << "插入元素之后的结果" << std::endl;L.print_list();// L.clear_list();// L.print_list();bool is_empty = L.is_empty();std::cout << "is_empty: " << is_empty << std::endl;     std::cout << "length: " << L.get_list_length() << std::endl;  Student s;L.get_element(3, s);std::cout << "第 3 个元素为 "  << "id:" << s.id << " "<< "name:" << s.name << " "<< "age:" << s.age << " "<< "gender:" << s.gender << " "<< std::endl;Student sd("004", "D", "female", 21);L.insert_element(4, sd);std::cout << "插入元素之后的结果" << std::endl;L.print_list();Student se;L.delete_element(4, se);std::cout << "要删除的元素为 "  << "id:" << se.id << " "<< "name:" << se.name << " "<< "age:" << se.age << " "<< "gender:" << se.gender << " "<< std::endl;std::cout << "删除元素之后的结果" << std::endl;L.print_list();Student sf("001", "A", "male", 20);std::cout << "要更改的元素为 "  << "id:" << sf.id << " "<< "name:" << sf.name << " "<< "age:" << sf.age << " "<< "gender:" << sf.gender << " "<< std::endl;L.update_element(sf);std::cout << "更新元素之后的结果" << std::endl;L.print_list();
}

数据结构(05)— 线性单链表实战相关推荐

  1. 数据结构(08)— 线性单链表基本操作

    1. 线性单链表数据结构 // 假定每个结点的类型用 SNode 表示 typedef struct SNodeTag {int data; // 所存储的数据元素SNodeTag *next; // ...

  2. python数据结构基础(单链表,多链表,二叉树)

    python数据结构基础(单链表,多链表,二叉树) 数据结构指数据对象中数据元素之间的关系 Python 给我们提供了很多现成的数据结构类型,这些系统自己定义好的,不需要我们自己去定义的数据结构叫做 ...

  3. 线性链表java实现_java实现线性单链表

    /** * * 线性单链表 */ public class LinkedLinearList { private Node head; private int length;// 实际长度 /** * ...

  4. 数据结构与算法--单链表相关面试题

    此文章仅作为自己学习过程中的记录和总结,同时会有意地去用英文来做笔记,一些术语的英译不太准确,内容如有错漏也请多指教,谢谢! 一.概述 获取单链表的有效元素个数[新浪面试题1] 获取单链表倒数第k个结 ...

  5. 数据结构之——《单链表》

    数据结构之--<单链表> 1.链表概念 2.链表分类 3.接口函数实现 1.链表概念 链表是一种物理存储结构上非连续,非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现. ...

  6. 数据结构精讲——单链表

    新手必会数据结构精讲--单链表 链表的介绍 概念:链表是一种物理存储结构上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 . 实际中链表的结构非常多样,以下情况组合起来就 ...

  7. [数据结构与算法] 单链表的简单demo

    Vc6之下编译通过.. 1 /******************************************************* 2 * @: Project: 单链表数据结构演示 3 * ...

  8. 线性单链表存储结构c语言代码,单链表定义-(线性表的链表存储结构)

    线性表分为:顺序存储结构和连存储结构 顺序存储结构的优点: 1.空间利用率高,几乎不需要额外的空间开销. 2.数据的逻辑结构和物理结构完全一致. 3.结点地址计算的时间和线性表的规模大小无关. 4.可 ...

  9. 头歌平台数据结构与算法 单链表实验 第1关:倒置链表

    任务描述 相关知识 实验目的 实验任务 实验说明 编程要求 测试说明 任务描述 本关任务:请在右侧编辑器的注释行填入适当内容来完成算法,以实现指定的功能,并通过运行来验证. 相关知识 实验目的 理解线 ...

最新文章

  1. Codeforces Round #699 (Div. 2) (A ~ F)6题全,超高质量良心题解【每日亿题】2021/2/6
  2. Android中脱离WebView使用WebSocket实现群聊和推送功能
  3. armel、armhf、arm64、armv7l 系统架构区别与联系(AArch64)
  4. PowerBI随笔(5)-关系模型与报表-2
  5. 简便解法:1004 成绩排名 (20分)
  6. linux什么用户什么任务,Linux 用户
  7. PHP面向对象 封装与继承
  8. Jmeter-Ant 生成测试报告
  9. Vue——知识体系总结
  10. 在python语言中定义私有成员变量的方法是_Python在类中有“私有”变量吗?
  11. MySQL-快速入门(3)运算符
  12. 孪生素数——C语言实现
  13. java 概率生成随机数_JAVA 生成随机数,并根据概率、比率
  14. 解决win10安装失败原因和方法
  15. 男孩取名分享:光彩夺目、聪明机灵的男孩名
  16. js实现点击切换checkbox背景图片
  17. 域渗透-横向移动(PTT)
  18. SCR-MCR:正则项, OGB榜单--清华唐杰-- 可扩展图学习
  19. 什么是序列化 怎么序列化 为什么序列化
  20. 鼠标作为画笔 | 八

热门文章

  1. kotlin中继承父属性使用构造方法
  2. Go 1.16 的这个新变化需要适应下:go get 和 go install 的变化
  3. Redis 笔记(15)— 管道 pipeline(客户端将批量命令打包发送用来节省网络开销)
  4. HJ86 求最大连续bit数
  5. 2022-2028年中国再生塑料颗粒行业市场全景调查及发展趋势分析报告
  6. scipy csr_matrix csc_matrix
  7. 协方差矩阵有什么意义?
  8. PyTorch里面的torch.nn.Parameter()
  9. Python如何调用matlab函数?
  10. 深度学习与TensorFlow