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

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

线性表是最简单和最常用的一种数据结构,他是由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,一经查实,立即删除!

相关文章

TForm1*Form1=newTForm1(this); Form1-Show();

TForm1*Form1newTForm1(this);Form1->Show();通过 Wiz 发布转载于:https://www.cnblogs.com/xe2011/archive/2012/06/03/2532874.html

[科研笔记] 关于人工智能与算法项目的思考

原链接&#xff1a;https://blog.csdn.net/walilk/article/details/77131929 前言   [科研笔记] 系列是我在科研道路上的随笔和思考&#xff0c;内容不加以局限&#xff0c;是一个开放的文章系列&#xff0c;这也是给自己一点自由的空间。      本文是我结合自身经验给的…

数据结构的基本概念和抽象数据类型

1、基本概念和术语 数据&#xff1a;是对客观事物的符号表示。 数据元素&#xff1a;数据的基本单位&#xff0c;一个数据元素可由若干个数据项组成&#xff0c;数据项是数据的不可分割的最小单位 数据对象&#xff1a;性质相同的数据元素的集合是数据的一个子集 数据结构&…

Jquery实现列表框效果

在java web开发中&#xff0c;我们经常要用到列表框&#xff0c;特别在系统的权限管理中&#xff0c;如上图所示&#xff0c;要实现如上效果&#xff0c;请看下面的源代码&#xff1a;源代码如下&#xff1a;<html><head><title>全选效果</title><s…

项目过程管理

项目过程管理 1. 项目所需要的文档&#xff08;需要归档&#xff09; 需求文档&#xff08;需求评审时的问题列表&#xff09;技术文档&#xff08;技术评审时的问题列表&#xff09;排期文档开发文档&#xff08;记录开发过程中遇到的难题和解决方案&#xff09;测试文档&am…

数据结构之指针复习

废话不多说&#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…

51与PC通信协议设计及实现(三):51部分模块化分工及设计

整个的51部分的伪代码简写如下&#xff1a; 1 void sendData() 2 {} 3 void time() 4 {} 5 void keysChecked() 6 { 7 return loca; 8 return key_state; 9 }10 main()11 {12 init();13 while(1)14 {15 if(keysChecked 1) //放到中断处理比较好16 …

管理机器学习项目

管理机器学习项目 一. 目录 传统的软件项目管理目前的现状机器学习项目管理 二、传统的软件项目管理 传统的软件项目管理和开发流程已经非常成熟。大致的流程如下&#xff1a; 由运营、产品进行最初的功能策划&#xff0c;进行可行性分析由项目经理召集相关人员进行产品启…

拖拽自动生成的DataGridView和BindingSource操作数据库(增加,修改,删除)---自己实现...

参考&#xff1a;http://hi.baidu.com/j2eedoc/blog/item/507ca70e1281c4e036d122dc.html using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Fo…

数据结构之结构体复习

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

高效管理读书笔记

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

C# 按钮美化技巧

(1)按钮 text设置成"" (2)按钮backgroundImage设置成 想要的图片 (3) ToolTip属性设置成 鼠标在上时的提示 (比如“搜索”、“删除”、“查找”)转载于:https://www.cnblogs.com/imihiroblog/archive/2012/06/08/2541940.html

蒙特卡罗方法介绍(一)

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

gawk手册

第一章 前言awk 是一个程式语言&#xff0c;对於资料的处理具有很强的功能。对於文 字档里的资料做修改、比对、抽取等的处理&#xff0c;awk 能够以很短的程式 轻易地完成。如果使用 C 或 Pascal 等语言写程式完成上述的动作&#xff0c; 会不方便且很花费时间&#xff0c;所写…

数据结构之malloc()函数动态内存分配复习

直接上代码分析 #include <stdio.h> #include <string.h> #include <malloc.h>int mian() {int a[5] { 1,5,8,46,12 };int len;printf("请输入你要分配数组的长度&#xff1a; len");scanf("%d", &len);int * pArr (int *)mallo…

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

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

标量函数,多语句表值函数,内嵌表值函数

标量函数返回一个标量(单值)结果,可返回Timestamp,text,Ntext,Image,Table,Cursor多语句表值函数&#xff0c;返回一条或多条Transact-sql语句建立的表,可在select 语句的FROM子句中被引用.内嵌表值函数&#xff0c;位于RETURN子句中的SELECT命令段从数据库中摔选出来的&#x…

ios初学笔记

bool值只取最低位的值&#xff0c;若最低位为&#xff10;&#xff0c;bool值等于NO&#xff1b;若最低位不为&#xff10;&#xff0c;bool值等于YES。比较bool值的时候&#xff0c;将变量与NO进行比较最保险。objc不支持多继承类的description方法类似java的toString方法&…

蒙特卡罗方法介绍( 二)

蒙特卡罗方法介绍( 二) 一、蒙特卡罗求解定积分 蒙特卡洛方法求解定积分有两种方法&#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…