实验一 线性表的顺序存储与实现_【自考】数据结构中的线性表,期末不挂科指南,第2篇

7f6464c9d941aa5d96710d953009b966.png

线性表

这篇博客写的是线性表相关的内容,包括如下部分,先看下有木有期待

  1. 啥是线性表
  2. 线性表的顺序存储
  3. 线性表的基本运算在顺序表上的实现
  4. 线性表的链式存储
  5. 线性表的基本运算在单链表上的实现
  6. 循环链表与双向循环链表

Over,内容还蛮多的!~  ̄□ ̄||,头大了...

首先明确一个非常重要的点

线性表是一个线性结构,注意上篇博客提过线性结构是数据的逻辑结构中的一种

基本概念

线性表是由n(n≥0)个数据元素组成的有穷序列

大白话:在内存上一个个排着,找到一个,剩下的挨着找就行

数据元素又称作结点

吐槽:人类在创造术语的路上就是这么带劲,上节课刚说数据元素又称元素,这又来一个结点,得,记住吧

结点个数叫做表长,那么我们用一张完整的图来说明一下

ada52e39f1beb67dcbb7577f21dfc0a6.png

线性表的基本运算,需要了解一下

  1. 初始化 Initiate(L)
  2. 求表长 Length(L)
  3. 读表元素 Get(L,i)
  4. 定位 Locate(L,i)
  5. 插入Insert(L,x,i)
  6. 删除Delete(L,i)

线性表的顺序存储

用顺序存储实现的线性表称为顺序表。一般使用数组来表示顺序表

接下就是刺激的时刻了,比较难的部分来了,因为要用C来实现线性表的基本运算

首先假定线性表的数据元素的类型为DataType ,这个DataType 可以是自定义的,也可以是默认的int,char等类型

const int Maxsize = 100 ;  // 预先定义一个足够大的常数
typedef struct{DataType data[Maxsize]; // 存放数据的数组int length ; // 顺序表的实际长度
} SeqList; // 顺序表类型名为SeqList  
SeqList L ;  // 定义一个L为顺序表

实现插入操作,函数名字为InsertSeqList(SeqList L,DataType x,int i) 表示在顺序表第i(1≤i≤n+1)个元素之前,插入一个新元素。使得线性表长度加1。

上面是逻辑上的C语言实现,接下来咱们先引用一个图,说明一下如何用C语言在内存上开辟一块空间,并且向里面存数据

#include <stdio.h>
#include <stdlib.h>const int Maxsize = 10;
typedef struct SeqList{int *data; //一个int指针,后面用来初始化数组用int length;
} seq;// 顺序表的初始化函数
seq init(){seq s;s.data = (int*)malloc(Maxsize*sizeof(int)); // 构造一个空的顺序表,动态申请存储空间if(!s.data) // 如果申请失败,退出程序{printf("初始化失败");exit(0);}s.length = 0; // 空表的长度初始化为0return s;
}

上述代码,相当于在内存上做了图示的操作

80d57f22bf39b10e645c40f07713cee2.gif

开辟空间之后,向每个小格子里面添加数字

void display(seq s){for(int i=0;i<s.length;i++){printf("%d",s.data[i]);}printf("n");}int main()
{seq s = init();//添加一个元素进入for(int i=1;i<=5;i++){s.data[i-1] = i;s.length++;}printf("初始化之后,表的数据为:n");display(s);return 0;
}

可以看动画理解

873fda761ce7923a610a0a3f5a137592.gif

添加元素完成之后,就是删除元素

删除的基本步骤 1. 结点a~i+1~,....a~n~依次向左移动一个元素位置 2. 表长度减1

看一下代码吧

seq delete_seq(seq s,int i){if(i<1||i>s.length){printf("位置错误");exit(0);}// 第i个元素下标修改为i-1for(int j=i;j<s.length;j++){s.data[j-1] = s.data[j];}s.length--;return s;
}

接下来实现定位的算法,说白了,就是判断一个值(x)的位置(i)

C语言的代码如下

// 注意,这个地方需要返回的为int了,也就是位置
int locate(seq s,int x){int i =0;while((i<s.length)&&(s.data[i]!=x)){i++;}if(i<s.length) return i+1;else return -1;
}

线性表的顺序存储的时间复杂度

|运算| 插入|删除|定位|求表长|读取元素| |--|--|--|--|--|--| | 时间复杂度|O(n) |O(n)|O(n)|O(1)|O(1)| 具体是怎么来的,需要你自己看看算法的实现喽,通过上述表格知道 顺序表的插入、删除算法在时间性能方面不是很理想,接下来我们就采用线性表的链接存储来看一下,是否存在优化。

线性表的链接存储

链式存储结构,上来需要记住有三种常见的 单链表循环链表双向循环链表

首先明确,单链表中每个结点由两部分组成

00f6cda16ef9f20ea9d8df190108a240.png

- data表示==数据域== - next表示==指针域==或==链域==

一些简单的结点概念

0acc1987f3ad22f93ba689b2bba615b1.png

线性表在单链表上实现基本运算

接下来重头戏来了,我们要用代码实现一个简单的单链表

空的单链表由一个头指针和一个头结点组成

初始化

初始化之前,我们需要先用C语言定义一个新的结构体

//链表中的每个结点的实现
//包含数据域与指针域
typedef struct node{int data;// 数据域,为了计算方便,类型设置为数字struct node *next; // 指针域,指向后继元素
} Node,*LinkList;

结构体定义好了之后,就可以开始初始化操作了 头结点初始化其实就是在内存上开辟一块空间,然后将指针域指向NULL

5c414e3d33f63c7a1c59914812840103.png

请看代码,注意返回的是一个指针类型,说白了就是头结点的地址

// 初始化
LinkList init(){Node *L; // 定义一个头结点L =(LinkList)malloc(sizeof(Node)); //头结点申请地址if(L == NULL){printf("初始化失败!n");exit(0);}L->next =NULL;return L;
}

初始化成功,开始插入元素

插入元素,有头插入、尾插、任意插

先说一下头插,当头结点初始化完毕之后,第一个元素插入进来就比较简单了,看动图 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20191110174036251.gif =400x) 这是插入一个元素,在用头插法插入第二个元素呢? ![在这里插入图片描述](https://img-blog.csdnimg.cn/20191110174900608.gif =500x) 新生成的pnew2首先将自己的指针域指向头结点的指针域pnew2->next = L.next,然后L.next = pnew2 即可

上述的逻辑写成代码如下

// 头插入法
void insert_head(Node *L){int i,n,num;  // n表示元素的个数 Node *pnew;printf("请输入要插入的元素个数:n = ");scanf("%d",&n);for(i=0;i<n;i++){printf("请输入第%d个元素: ",i+1);scanf("%d",&num);pnew = (LinkList)malloc(sizeof(Node));pnew->data = num; // 将数字存储到数据域pnew->next = L->next; // 指针域指向L(头结点)的指针域L->next = pnew; // 头结点指针域指向新结点地址}
}

接下来看一下尾插法,其实理解起来也不难,说白了就是在链表后面追加元素即可 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20191110180601505.gif =600x) 代码如下,这个地方看一下里面有一个p=L请问直接使用L可以吗?为什么不直接用,搞清楚了,你也就明白了

// 尾插法
void insert_tail(Node *L){int i,n,num;Node *p,*pnew;p = L;printf("要输入元素的个数:n = ");scanf("%d",&n);for(i=0;i<n;i++){printf("请输入第%d个元素:",i+1);scanf("%d",&num);pnew = (LinkList)malloc(sizeof(Node));if(pnew == NULL){printf("初始化失败");exit(0);}pnew->data = num;p->next = pnew;p = pnew;}p->next = NULL;}

剩下的算法实现就比较简单了,例如求表长,通过循环的方式,计算一下即可

//求表长
int get_length(LinkList L){LinkList p;int length = 0;p = L->next;   // p 指向第一个结点while(p){printf("单链表的数据为%dn",p->data);length++;p = p->next;}return length;
}

读表中的元素

// 读表中的元素
LinkList get_element(LinkList L,int i){// 在单链表L中查找第i个结点,若找到,则返回指向该结点的指针,否则返回NULLNode *p;p = L->next;int position = 1;while((position<i)&&(p!=NULL)){ // 当未到第i结点且未到尾结点时继续后移p = p->next;position++;}if(i==position) return p; //找到第i个结点else return NULL;   // 查找失败
}

读取表的元素,还可以按照值去找,返回位置,尝试一下吧,写起来都是比较容易的

int get_element_by_data(LinkList L,int x){Node *p;p = L->next;int i = 0;while(p!=NULL && p->data == x){p = p->next;i++;}if (p!=NULL) return i+1;else return 0;
}

写个复杂点的,在任意位置插入一个元素,这个还是好玩一些的

/在任意位置插入元素,x为要插入的内容,i为插入的位置
void insert(LinkList L,int x,int i){Node *p,*q; //p表示要插入的元素,q表示要被插入的元素if(i==1) q = L; //如果i==1,那么p=L进行初始化操作else q = get_element(L,i-1); // 找到第i-1个元素if(q==NULL){printf("找不到位置");exit(0);}else{p =(LinkList)malloc(sizeof(Node));p->data = x;p->next = q->next; // 新生成的p指向q的下一个结点q->next = p;//q的指针域指向新生成的p}
}

简单说明一下吧 大白话为 要在第i个位置插入一个元素x,那么需要找到i-1位置的元素,这个元素叫做 q

让新元素p(数据域为x,指针域为空)的指针域指向第i 元素,也就是q原先的指针域,==防止丢失掉==

然后在叫q的指针域指向p的地址即可,如果还不明白,看图

5408fd139d527ecc394b48b2e471ec45.png

对于删除任意位置的节点,这个就要留给你自己了

如果将a~i~移除链表,需要找到直接前驱,让直接前驱的指针域指向a~i+1~的地址就可以了

记得,通过free(p)释放结点

删除全部结点也需要自己完成一下,尽量把代码写完哦~~~

单链表的时间复杂度

  • insert(LinkList L,int x,int i) 时间复杂度为O(n^2^)
  • 头插法和尾插法时间复杂度为O(n)

循环链表

环状链表只需要将表中最后一个结点的指针指向头结点,链表就形成了一个环 如图

6bc2f767124442b2d13946764013aa81.png

循环链表如何想研究一下可以去实现约瑟夫环,由于本教材中不是重点,所以选修即可

双向循环链表

双向循环链表就是在单链表中的每个结点在增加一个指向直接前驱的指针域prior ,这样每个结点就有两个指针了

66b5a652f346e8a52f13b5945bb1b0b7.png

注意点 1. 双向循环链表是一种对称结构,即可以直接访问前驱结点又可以直接访问后继结点,所以找前驱和后继结点的时间复杂度都是O(1),也可以得到结论双向循环链表适合应用在需要经常查找结点的前驱和后继场合 2. p = p->prior->next = p->next->prior

教材中重点给出了删除和插入的两个逻辑,我们看一下

// p表示的是待删除的结点
p->prior->next = p->next;
p->next->prior = p->prior;
free(p)

图示如下

c3defce9f12a3214656b876d0aad87e8.png

大白话 先让p等于要删除的结点,然后把p删除前,需要将p的前驱和后继结点连接起来,刚才的代码干的就是这个事情!

插入逻辑

在p所指的结点后面插入一个新结点*t,需要修改四个指针:
t->prior = p;
p->next = t;  // 这两个步骤将t和p连接起来了t->next = p->next;
p->next->prior = t; //这两个步骤将t和p后继结点连接起来了

期末考试

这章是期末考试或者自考的一个比较重要的考试章节,一般会出现算法设计题,难度系数挺高的

建议,在能力范围内用C语言实现顺序表的基本运算,实现单链表的基本运算

懵了吧,嘿嘿~,多看几遍,多看几遍,看图,看图,写代码,运行,运行

欢迎关注,梦想橡皮擦公众号哦~

6de2c87e9a8bd065fa7b2d89dccb7bde.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/542697.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

二叉树打印叶子节点,非递归_使用递归打印链接列表中的备用节点

二叉树打印叶子节点,非递归Solution: 解&#xff1a; Input: A singly linked list whose address of the first node is stored in a pointer, say head 输入&#xff1a;一个单链表 &#xff0c;其第一个节点的地址存储在指针中&#xff0c;例如head Output: The alternati…

TYVJ P1012 火柴棒等式 Label:枚举

背景 NOIP2008年提高组第二题描述 给你n根火柴棍&#xff0c;你可以拼出多少个形如“ABC”的等式&#xff1f;等式中的A、B、C是用火柴棍拼出的整数&#xff08;若该数非零&#xff0c;则最高位不能是0&#xff09;。用火柴棍拼数字0-9的拼法如图所示&#xff1a;注意&#xff…

java math max_Java Math类静态double max(double d1,double d2)示例

java math max数学类静态double max(double d1&#xff0c;double d2) (Math Class static double max(double d1,double d2) ) This method is available in java.lang package. 此方法在java.lang包中可用。 This method is used to return the maximum one of both the give…

python怎么开发软件_怎么使用python进行软件开发

一、下载pyinstaller 我使用的版本为PyInstaller-2.1&#xff0c;支持python版本2.3-2.7&#xff0c;点击这里下载。 二、安装pyinstaller 下载完成后&#xff0c;解压即可。我的解压目录为D:\Python27\PyInstaller-2.1\ 三、使用pyinstaller打包.py成.exe应用程序 1.注意使用前…

28、清华大学脑机接口实验组SSVEP数据集:通过视觉触发BCI[飞一般的赶脚!]

前言&#xff1a; 哈喽&#xff0c;最近对清华大学脑机接口的数据进行了尝试&#xff0c;输入到了DL模型中&#xff0c;以下是本人对于清华BCI数据的个人见解。 数据地址&#xff1a; 清华大学脑机接口研究组 (tsinghua.edu.cn) 打开网站可以看到有很多个数据&#xff0c;官…

python Pexpect

http://www.cnblogs.com/dkblog/archive/2013/03/20/2970738.htmlhttp://www.ibm.com/developerworks/cn/linux/l-cn-pexpect2/index.htmlhttp://www.cnblogs.com/dkblog/archive/2013/03/20/2970738.htmlpython Pexpect Pexpect 是一个用来启动子程序并对其进行自动控制的纯 P…

python 幂运算 整数_在Python中检查一个数字是否是另一个数字的幂

python 幂运算 整数To solve this problem simply, we will use the log() function from the math module. The math module provides us various mathematical operations and here we will use the log() function from this module. In Python working of log() function, …

3dmax镜像后模型线条乱了_3dMax入门教程来啦!小白赶紧收藏!

3D Studio Max&#xff0c;常简称为3d Max或3ds MAX&#xff0c;是Discreet公司开发的&#xff08;后被Autodesk公司合并&#xff09;基于PC系统的三维动画渲染和制作软件&#xff0c; 3dmax软件主要功能有建模&#xff0c;动画&#xff0c;渲染&#xff0c;特效等&#xff0c;…

java中哲学家就餐死锁_哲学家就餐问题与死锁总结

死锁的四个条件&#xff1a;(1) 互斥条件&#xff1a;一个资源每次只能被一个进程使用。(2) 请求与保持条件&#xff1a;一个进程因请求资源而阻塞时&#xff0c;对已获得的资源保持不放。(3) 不剥夺条件:进程已获得的资源&#xff0c;在末使用完之前&#xff0c;不能强行剥夺。…

linux扫描工具之nmap

Linux下有很多强大网络扫描工具&#xff0c;网络扫描工具可以分为&#xff1a;主机扫描、主机服务扫描、路由扫描等,nmap支持批量主机扫描和主机服务扫描。检测安装&#xff1a;[rootbier ~]# rpm -qa nmap nmap-5.51-4.el6.x86_64如果没有安装就安装一下nmap的安装直接使用&am…

如何将多个一维列表转化为二维列表_数据分析2_如何处理一维、二维数据

吞一块大饼&#xff0c;还不如切成小块吃得香常见的数据集&#xff0c;要么是数列&#xff0c;要么是表格&#xff1b;因此&#xff0c;数据分析最首要的是&#xff0c;处理一维、二维数据。主要知识点可参考如图。如需要&#xff0c;可点击以下百度网盘链接下载数据分析基础知…

关于java中锁的面试题_Java面试题-Java中的锁

1. 如何实现乐观锁(CAS)&#xff1f;如何避免ABA问题&#xff1f;答&#xff1a;1)读取内存值的方式实现了乐观锁(比如&#xff1a;SVN系统)&#xff0c;方法&#xff1a;第一&#xff0c;比较内存值和期望值&#xff1b;第二&#xff0c;替换内存值为要替换值。2)带参数版本来…

NSUserDefaults

2019独角兽企业重金招聘Python工程师标准>>> NSUserDefaults 转载于:https://my.oschina.net/18829297883/blog/737931

什么是算术运算和逻辑运算_8086微处理器的算术和逻辑运算

什么是算术运算和逻辑运算逻辑指令 (Logical Instructions) a) AND: Logical AND a)AND&#xff1a;逻辑AND Atleast one of the operant should be a register or a memory operant both the operant cannot be a memory location or immediate operant. 操作中的至少一个应该…

python文件读写用到的库_Python使用pyshp库读取shapefile信息的方法

通过pyshp库&#xff0c;可以读写shapefile文件&#xff0c;查询相关信息&#xff0c;github地址为 import shapefile # 使用pyshp库 file shapefile.reader("data\\市界.shp") shapes file.shapes() # print(file.shapetype) # 输出shp类型null 0 point 1 poly…

h5引入json_Vue中如何使用本地Json文件?

我需要将菜单配置成Json文件&#xff0c;然后再程序中引入{{menu.name}}import menuListConfig from ../../config/menu.jsonexport default {name: "Sider",data(){return {menuList:JSON.parse(JSON.stringify(menuListConfig))}}}需要如何做&#xff0c;才能v-for…

深入学习jQuery选择器系列第四篇——过滤选择器之属性选择器

前面的话 属性过滤选择器的过滤规则是通过元素的属性来获取相应的元素&#xff0c;对应于CSS中的属性选择器。属性过滤选择器可分为简单属性选择器、具体属性选择器和条件属性选择器三种。本文将详细该部分内容 简单属性选择器 [attribute] [attribute]选择器选择拥有该属性的元…

c++ scanf读取_使用scanf()读取内存地址并在C中打印其值

c scanf读取Here, we have to input a valid memory address and print the value stored at memory address in C. 在这里&#xff0c;我们必须输入一个有效的内存地址并在C中打印存储在内存地址中的值。 To input and print a memory address, we use "%p" format…

python正则匹配_Python正则表达式只匹配一次

我正在尝试创建一个简单的降价乳胶转换器,只是为了学习 python和基本的正则表达式,但我不知道试图弄清楚为什么下面的代码不起作用&#xff1a; re.sub (r\[\*\](.*?)\[\*\]: ?(.*?)$, r\\footnote{\2}\1, s, flagsre.MULTILINE|re.DOTALL) 我想转换像&#xff1a; s "…

Virtual Network (1) - How to use it in a guest

本文将讲述一个问题&#xff1a;kvm guest使用libvirt xml定义如何使用virtual network&#xff1f;1&#xff09;nat&#xff0c; route &#xff0c;isolated, open类型在host中定义virtual network会创建一个虚拟的bridge&#xff0c;相当于一个交换机。guest只需要连接到这…