线性表的定义和基本运算之线性结构

一、线性表的逻辑定义和性质

线性表是最简单和最常用的一种数据结构,他是由n个数据元素(结点)a1,a2,a3,a4........an组成的有限序列。其中,数据元素个数那位表的长度。当n为0时称为空表,非空的线性表通常记为 (a1,a2,a3,a4........ai-1,ai,..........an)

这里的元素ai(0< i < n+1) 是一个抽象的符合,他可以是一个数或者一个符合,还可以是较复杂的记录。

从线性表的定义可以看出呀的逻辑特征,对于一个非空的线性表:

(1)有且仅有一个称为开始元素的a1,它没有前驱,仅有一个直接的后继a2

(2)有且仅有一个称为终端元素的an,它没有后继,仅有一个直接前驱an-1

(3)其余元素ai(1< i <n)称为内部元素,他们都有且仅有一个直接前驱ai-1和一个直接后继ai+1

二、线性表上的定义和基本运算

(1)对于线性表InitList(L),构造一个空的线性表L

(2)求表长ListLength(L),返回线性表L中元素的个数,即表长

(3)取表中第i个元素GetNode(L,i),若 0<i<ListLength(L)+1,则返回第i个元素ai

(4)按值查找LocateNode(L,x),在表L中查找第一个值为x的元素,并返回该元素在表L中的位置,若表中没有元素的值为x,则返回0值

(5)插入 InsertList(L,i,x),在表L的第i个元素之前插入一个值为x的新元素,表L的长度加1

(6)删除 DeleteList(L,i),删除表L的第i个元素,表L的长度减1

 

二、线性表的两种实现方式

1.1顺序表示(顺序表)

概念:用一组地址连续的存储单元依次存储线性表的数据元素,这种存储结构的线性表称为顺序表。

特点:逻辑上相邻的数据元素,物理次序也是相邻的。

  只要确定好了存储线性表的起始位置,线性表中任一数据元素都可以随机存取,所以线性表的顺序存储结构是一种随机存取的储存结构,因为高级语言中的数组类型也是有随机存取的特性,所以通常我们都使用数组来描述数据结构中的顺序储存结构,用动态分配的一维数组表示线性表。

1.2 代码实现

以最简单的学生信息管理为例:

首先先创建两个数据结构,如下:

#define maxsize 100 //定义学生最大数量
#define OK 1       //正确标志
#define ERROR 0     //失败标志
//学生信息的数据结构
typedef struct{int id;   //学生idchar name[30];   //学生姓名   
}Student;//顺序表数据结构
typedef struct{Student *elem;   //储存空间的基地址int length;      //数据结构的长度
}SqList;//定义SqList类型的变量
SqList L;

这是一个十分简单的例子,这样我们就可以通过L.elem[i-1]访问序号为i的学生信息了。其实这里我们用到了指针数组。如果你对指针数组还不熟悉的话,可以去另一篇文章看看:https://blog.csdn.net/qq_38378384/article/details/79951651

1.初始化

基本算法:

   //初始化顺序表基本算法Status InitList(SqList &L){//构造一个空的顺序表LL.elem = new ElemType[maxsize];  //分配内存空间if(!L.elem) exit(-1);L.length = 0;return OK;}

2.取值

基本算法:

//顺序表取值Status Get(SqList &L,int i,ElemType &e) {if(i<1||i>L.length)  return ERROR;e = L.elem[i-1];return OK;       }

3.查找

基本算法:

//顺序表查找int Find(SqList L,ElemType e) {//查找值为e的数据元素,返回其序号for(i=0;i<L.length;i++){if(L.elem[i]==e) return i+1;}return ERROR;   //查找失败   }

4.插入

基本算法:

//顺序表插入Status ListInsert(SqList &L,int i,ElemType e){if((i<1)||(i>L.length+1)) return ERROR;  //i不合法if(L.length == maxsize) return ERROR;  //满了for(j=L.length-1;j>=i-1;j--)L.elem[j+1]=L.elem[j]; //将第n个至i个位置的元素后移L.elem[i-1]=e; //将e放进第i个位置}

5.删除

基本算法:

 //顺序表删除Status ListDelete(SqList &L,int i){//删除第i个元素,i的值为[1,L.length]if((i<1)||(i>L.length)) return ERROR;for(j=i;j<=L.length-1;j++)L.elem[j-1]=L.elem[j];--L.length;  //长度减一return OK;}

算法都十分的简单,眼尖的你可能发现了,为啥有的参数用的是引用,有的不是呢?

这里我就得讲下使用引用作为形参的作用了,主要有三点:

(1)使用引用作为参数与使用指针作为参数的效果是一样的,形参变化时实参对应也会变化,这个我在上篇文章(我上面给的链接)也有说明,引用只是一个别名。

(2)引用类型作为形参,在内存中并没有产生实参的副本,而使用一般变量作为形参,,形参和实参会分别占用不同给的存储空间,当数据量较大时,使用变量作为形参可能会浪费时间和空间。

(3)虽然使用指针也可以达到引用一样的效果,但是在被调函数中需要重复使用"*指针变量名"来访问,很容易产生错误并且使程序的阅读性变差。

此时你会发现,使用顺序表作为存储时,空间是一次性直接开辟的,所以可能会有空间不足或者浪费空间的情况出现,那么为啥不用一个就分配一个空间呢,再使用一个方式将这些空间串起来不就好了,是时候展现真正的技术了(链表)。

2.1链表

概念:用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的),包括数据域和指针域,数据域存数据,指针域指示其后继的信息。

这里重点讲单链表,如图:

2.1代码实现

//单链表存储结构typedef struct LNode{ElemType data;   //数据域struct LNode *next; //指针域}LNode,*LinkList;

为了提高程序的可阅读性,在此对同一结构体指针类型起了两个名称,LinkList与LNode*,本质上两者是等价的。通常习惯上用LinkList定义单链表,强调定义的是某个单链表的头指针,用LNode *定义指向单链表中任意结点的指针变量。

例如,定义LinkList L,则L为单链表的头指针,若定义LNode *p ,则p为指向单链表中某个结点的指针,用*p代表该结点。

1.初始化

基本算法:

//初始化 Status InitList(LinkList &L){//构造一个单链表L=new LNode;  //生成头结点,用头指针L指向头结点L->next =NULL;  return OK;     }


2.取值

基本算法:

//取值Status Get(LinkList L,int i,ElemType &e) {//在带头结点的单链表L中根据序号I获取元素的值,用e返回L中第i个数据元素的值p=L->next;j=1;//计数器while(p&&j<i)     {  //顺着链表向后扫描,直到j==ip=p->next;++j;}if(!p||j>i) return ERROR; //不合法e=p->data;   //找到该结点后获取该结点的数据域return OK; }


3.查找

基本算法:

//查找LNode *Find(LinkList L,ElemType e) {p=L->next; //使p指向首元结点while(p && p->data!=e){p=p->next;  //不符合条件就一直滚下去}return p;   //这里有两种情况,找到的时候返回指针p,如果找不到那么这个p则为null,因为最后一个指向的是null}


 

4.插入

基本算法:

//插入
Status ListInsert(LinkList &L,int i,ElemType e){//在带头结点的单链表L中第i个位置插入值为e的新结点p=L;j=0;while(p&&(j<i-1)){p=p->next;         //查找第i-1个结点,p指向该结点++j;}if(!p||j>i-1) return ERROR;s=new LNode;   //生成一个新结点s->data=e;   //将结点*s的数据域置为es->next=p->next; //先接尾部p->next=s;  //再接头部
}


 

5.删除

基本算法:

//删除
Status ListDelete(LinkList &L,int i){//删除第i个元素p=L;j=0;while((p->next)&&(j<i-1)){p=p->next;    //查找i-1个结点++j;}if(!(p->next)||(j>i-1)) return ERROR;  //当i>n或i<1时,不符合条件q=p->next;   //临时保存被删除的地址p->next=q->next;  //将前驱结点指向后驱delete q;  //释放删除结点的空间return OK;
}

 

其实单链表可以想象成一列人在玩游戏,每个人都把手搭到后面那个人的肩膀上,每个人身上都有一个大口袋用来放数据,最后一个人没人可以搭就一直悬空着,第一个带头领队的就不用口袋了,它是一个头结点,是用来找到第一个有口袋的人的,也就是首元结点。

  这样想的话就简单了,初始化的时候就是用一个人当头结点,它没有口袋,他的手是用来搭到第一个有口袋的人肩膀的,因为这个人还没来,所以它的next是Null,而取值时,通过参数i,我们就可以从首元结点开始数,数到第i个人,找到他后,就可以拿他口袋里面的东西,查找是知道口袋里面东西是什么,想找到这个东西的拥有者,也是一样从首元结点开始找。遍历下去,插入的话,比如要插入第i个位置,那么我们就先找到第i-1个人,然后让新来的手搭到第i个人身上,然后再让第i-1个人把之前放在第i个人的手挪开,放在新来的人的肩膀上,删除操作的话,例如删除第i个人,那么也是先找到第i-1个人,这里的重点是,因为链表的查询只能是从头开始找的,是不能逆回去的,所以我们需要找个变量把要删的那个人的地址先存起来,然后把第i-1个的手放到第i+1个人身上,如果我们不找个变量把那个人的地址存起来,这时候我们就没办法找到他了,因为我们用一个变量临时保存他的地址,于是我们只需要释放这个地址的空间就可以了。

这就是单链表的基本操作,那么如何创建单链表呢?

主要有着两种方法(前插法和后插法)

//前插法创建单链表

 void CreateList(LinkList &L,int n) {//逆次序输出n个元素的值L=new LNode;L->next=NULL;for(i=0;i<n;++i) {p=new LNode;  //生成新结点cin>>p->data;  //输入新结点的数据域内容p->next=L->next; //将新结点插到头结点之后L->next=p;}}


 //后插法

void CreateList(LinkList &L,int n){//正次序输入n个元素的值L=new LNode;L->next=NULL;  //建立一个带头结点的空链表r=L;   //尾指针r指向头结点for(i=0;i<n;++i) {p=new LNode; //生成新结点cin>>p->data; //输入新结点的数据域内容p->next=NULL;r->next=p;  //将新结点插入尾结点之后r=p;   //改变尾指针,使其指向新的尾结点}}


  两种方式的结果是一样的,区别就是前插法是把新的元素插到最前面,代替了首元结点的位置,就是明摆的插队,而后插法是插到最后面,有点类似于队列。而且后插法多了一个用来指向尾结点的尾指针。

 实际上链表还有两种,双向链表和循环链表,循环链表用的比较多,就是把头和尾连起来了,像一个圈一样。这里我就不说明了,因为只要懂了单链表,另外两种理解起来是十分容易的事情。
 

 

 

 

 

 

 

 

 

 

 

 

 

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

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

相关文章

数据结构之指针复习

废话不多说&#xff0c;拿起键盘就是干&#xff0c;直接上代码&#xff1a; #include <stdio.h>int main() {double *p;double x 66.6;p &x; //x占8个字节&#xff0c;一个字节占8位&#xff0c;一个字节一个地址double arr[3] { 1.1,2.2,3.3 };double *q;q &a…

数据结构之结构体复习

为什么出现结构体&#xff1f; 为了表示一些复杂的数据&#xff0c;一些基本数据类型无法满足要求&#xff0c; 当要用一个变量描述一个对象的多个属性时&#xff0c;普通的内置数据类型是表示不了的&#xff0c;这个时候就可以用结构体回。结构体和类很相似&#xff0c;唯一不…

高效管理读书笔记

高效管理读书笔记一、优秀的权威宣言二、主要的内容要点2.1 有权威的领导都会关心自己的员工2.2 问责而不指责2.3 多点尤达&#xff0c;少点超人三、原书一、优秀的权威宣言 优秀的权威就是&#xff1a; 指出大部分人视而不见的问题的气质今天畅所欲言而不是空等明天的好心【…

蒙特卡罗方法介绍(一)

蒙特卡罗方法介绍(一) 一、蒙特卡罗方法的基本思想和解题步骤 1.1 蒙特卡罗方法的基本思想 蒙特卡罗方法也称随机模拟法、随机抽样技术或统计实验发&#xff0c;其基本思想是&#xff1a;为了求解数学、物理、工程技术或生产管理等方面的问题。首先&#xff0c;建立一个与求…

神策数据张涛:如何让用户标签价值落地?

本文根据神策数据副总裁张涛在《用户个性化运营—标签体系搭建新机遇》主题沙龙中演讲整理所得。 标签系统&#xff0c;在企业中已不是什么“高大上”的说辞。然而让用户标签价值真正落地企业不多&#xff0c;就像“青少年谈性”&#xff0c; 有一段话形容得再贴切不过&#xf…

蒙特卡罗方法介绍( 二)

蒙特卡罗方法介绍( 二) 一、蒙特卡罗求解定积分 蒙特卡洛方法求解定积分有两种方法&#xff0c;一种是上一节中讲的投点法&#xff0c;另外一种是期望法&#xff08;也称平均值法&#xff09;。 1.1 投点法 给出如下曲线f(x)f(x)f(x),求f(x)f(x)f(x)在a,ba,ba,b上的积分&am…

大数据技术之kafka (第 3 章 Kafka 架构深入) 分区策略在分析

如果不懂分区策略请看我之前的文章&#xff1a;https://blog.csdn.net/ywl470812087/article/details/105328015 默认的方式我们采用的是Range策略方式&#xff08;按主题给消费者消费&#xff0c;主题被谁订阅了就谁消费&#xff09; 先看下下面这个图&#xff0c;画的很丑&a…

如何达成目标笔记

如何达成目标 一、本书主要内容 推荐序一 升级你的行动工具箱 推荐序二 人们可以改变 引言 成功者和自制力的悖论 //004 自制力到底是怎样的 //007 你能做什么 //009 本书的主题 //011 1.1 准备就绪 第1章 你明白自己去往哪里吗 别说“做到最好” //017 大局与细节 //…

大数据技术之 Kafka (第 4 章 Kafka API ) Producer API

4.1.1 消息发送流程 Kafka 的 Producer 发送消息采用的是异步发送的方式。在消息发送的过程中&#xff0c;涉及到了两个线程——main 线程和 Sender 线程&#xff0c;以及一个线程共享变量——RecordAccumulator。main 线程将消息发送给 RecordAccumulator&#xff0c;Sender…

《关键对话——何谓关键对话》读书笔记(一)

《关键对话——何谓关键对话》读书笔记&#xff08;一&#xff09; 利用假期的时间&#xff0c;将关键对话阅读了一遍&#xff0c;书中提到的观点&#xff0c;方法&#xff0c;场景等很适合我目前处的状态&#xff0c;有的时候读起来仿佛就是自己身临其境&#xff0c;有种感同身…

从java读取Excel继续说大道至简 .

在上一篇博客《从复杂到简单&#xff0c;大道至简》中说道我们要把复杂的问题简单化&#xff0c;也就是要把问题细分&#xff0c;让大问题变成小问题&#xff0c;这样解决起来会相对容易&#xff0c;当我们把容易的小问题解决掉了&#xff0c;大问题自动就会迎刃而解。 所以今天…

推荐算法工程师的成长之道

推荐算法工程师的成长之道 原创&#xff1a; gongyouliu 大数据与人工智能 3月20日 源链接&#xff1a;原文地址 本文&#xff0c;作者会基于自己的实践经验讲述推荐算法工程师的成长之道&#xff0c;这里的“道”有发展路径和道(道理、方法论、经验、智慧)两层意思。 所以本文…

java电子商务源码解读 b2b2c o2o

大型企业分布式互联网电子商务平台&#xff0c;推出PC微信APP云服务的云商平台系统&#xff0c;其中包括B2B、B2C、C2C、O2O、新零售、直播电商等子平台。 分布式、微服务、云架构电子商务平台 java b2b2c o2o 技术解决方案 开发语言&#xff1a; java、j2ee 数据库&#x…

信息流推荐多样性

信息流推荐多样性 一、问题现状 信息流产品中一个常见的问题是多样性越来越差&#xff0c;造成这种问题的原因在于机器学习算法本身。下面通过一副系统循环图来介绍多样性差的问题。 资讯库随机推荐文章&#xff0c;由于是按照全库比例采样&#xff0c;娱乐占比较大&#xf…

Robocode教程2——你的第一个robo,取个好名字哦

摘自&#xff1a;http://site.douban.com/widget/notes/7736245/note/210029011/ 你需要准备的东西&#xff1a;1.c语言的知识和一点点的java知识&#xff0c;robocode意在学习java&#xff0c;不要要太深的java水平&#xff0c;你只要理解java和c的区别就可以了。2.robocode A…

UI设计师的面试过程

Palantir Technologies是一家提供分析、整合、可视化各种数据的IT型技术公司。在该公司&#xff0c;前端工程师和后端工程师有同样的面试过程&#xff0c;前端工程师也需要的一定的编程基础。该公司技术博客Palantir TeckBlog日前发表了一篇博文《The UI Design Interview》&am…

数据在市场运营中的应用

数据在市场运营中的应用 1. 背景 目前的产品运营、用户拉新、渠道投放、留存等都是靠人工进行策略制定&#xff0c;有的公司和部门完全靠着以前的经验在尝试互联网产品的市场营销和运营。这样不仅效率很低&#xff0c;而且效果也不显著。 主要存在的问题有以下几点&#xff…

信息流项目计划和思路

目录 一、对项目的认识. 4 1&#xff0e;用户需求和竞品. 4 2. 项目现状. 4 3. 发展前景. 4 二、项目的业务方向和思路. 6 1. 业务方向. 6 2. 2020年目标. 6 3. 思路. 6 3.1用户留存提升&#xff08;6%->12%&#xff09;. 6 3.2日活提升&#xff08;30万->80万…

MySQL学习笔记_关于MySQL的字符类型VARCHAR长度知识总结

MySQL学习笔记_关于MySQL的字符类型VARCHAR长度知识总结 一.VARCHAR存储和行长度限制 1.VARCHAR(N)中&#xff0c;N指的是字符的长度,VARCHAR类型最大支持65535,指的是65535个字节,但并不支持65535长度的varchar&#xff0c;65535中应该包含了所有字段的长度、变长字段长度标示…