学习408之数据结构--线性表-顺序表 学会动态顺序表的创建

线性表

线性表(inear list)是n个具有相同特性的数据元素的有限序列。
线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串等
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以
数组和链式结构的形式存储

首先线性表是一个序列,元素之间是有顺序的,若元素存在多个,则第一个元素无前驱,最后一个元素无后继,其他每个元素都有且只有一个前驱和后继。
其次,线性表强调是有限的,其中的元素是有限的。

比如,要实现两个线性表集合A和B的并集操作。即要使的集合A=A并集B。也就是将存在于B中,不存在于A中的元素插入进集合A中。
我们假设La表示集合A,Lb表示集合B,则实现的代码如下:

/*将所有的在线性表Lb中但不存在La中的数据元素插入到La中*/
void unionL(Sqlist *La, Sqlist Lb)
{int La_len, Lb_len;ElemType e;                    /* 声明与La和Lb相同的数据元素e */La_len = Listlength(*La);      /* 求线性表的长度 */Lb_len = Listlength(Lb);for (int i = 1; i <= Lb_len; i++){GetElem(Lb,i,&e);				/* 取Lb中第i个数据元素赋给e */if (!LocateElem(*La, e))		/* La中不存在和e相同数据元素 */ListInsert(La,++La_len,e);  /* 插入 */}
}

顺序表

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。

顺序表一般可以分为:

1.静态顺序表:使用定长数组存储。
2.动态顺序表:使用动态开辟的数组存储。

//代码一
// 顺序表的静态存储
#define N 100
typedef int SLDataType;
typedef struct SeqList
{SLDataType array[N]; // 定长数组         //数组的大小size_t size; 				// 有效数据的个数    //线性表的大小
}SeqList;

看代码一,我们可以发现描述顺序存储结构需要三个属性:

1.存储空间的起始位置:数组array它的存储位置就是存储空间的存储位置;
2.线性表的最大存储容量:数组长度N;
3.线性表的当前长度: size。

// 顺序表的动态存储
typedef struct SeqList
{SLDataType* array; // 指向动态开辟的数组size_t size; 			// 有效数据个数size_t capicity; // 容量空间的大小
}SeqList;

代码二,原理与代码一无太大差别,只是数组的空间大小由静态变为动态的了。在数组每次满载时,进行判断进行增容capicity的大小。

(一)数据长度与线性表长度的区别

我们需要了解的是数组是我们创建出用来存放元素的存储空间,它的大小是固定的或是动态的。
而结构体中的size所表示的是我们创建线性表中的元素的个数,随着线性表插入和删除操作的进行,这个值是发生改变的。
在任意时刻,线性表的长度都应该小于等于数组的长度(否则出现访问越界的情况)。
我们明白选择数组的特点之一就是我们可以通过下标访问到我们想要的元素,在数组中我们排序也是从0开始的(须注意就是数组的下标),所以将线性表的元素存储在数组中,线性表中的第 i 个元素就是在数组下标为 i-1 的位置,即数据元素的序号和存放它的数组下标之间存在对应关系。
image.png

存储器中的每个存储单元都有自己的编号,这个编号成为地址。

假设占用的是 c 个存储单元,那么线性表中第 i+1(下标) 个数据元素的存储位置和第 i 个数据元素的存储位置满足下列关系(LOC表示获得存储位置的函数)。

LOC(ai+1) = LOC(ai)+c;

所以对于第 i 个数据元素ai的存储位置可以有a1推算得出

*LOC(ai) = LOC(a1) + (i-1)c;

通过此公式,可以随时算出线性表中任意位置的地址。对于计算机来说,对每个线性表位置的存入或者取出数据,都花费相同的时间,也就是一个常数,因此它的时间复杂度就是O(1)。我们通常把具有这一特点的存储结构称为随机存取结构

(二)动态顺序表的实现

静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。

1.为了方便管理和提高代码的可读性,创建不同的文件来放置代码。

image.png
list.h用于放置所需头文件和宏,以及函数的声明
list. c用于放置函数的定义,通常于设置头文件的名字一致,便于与test. c分辨
test. c中放置主函数,作为一个菜单操作界面,使用所设计的函数。

2.我们可以联系之间学习的通讯录的原理参考使用

但是基于我们现在的目的是学习动态顺序表,所以我们尽量保持测试数据的便于调试(保证遇到问题时,可以快速找到问题)。
要求对线性表中的元素进行增删查改。
须注意,我们在学习C语言时就了解到使用动态内存的操作:
申请动态内存后,要确保使用的是成功申请了内存的空间,其次是使用结束后要释放空间,并将指向该空间的指针置为NULL。

3.创建结构体

结构体为了更好观察与全局的使用,我们将其建立在list头文件中。

//"list.h"
#include <stdio.h>
// 顺序表的动态存储
typedef struct SeqList
{SLDataType* array; // 指向动态开辟的数组size_t size; // 有效数据个数size_t capicity; // 容量空间的大小
}SL;

4.test.c

基于顺序表的功能前,我们需要最基本的两步,初始化和销毁。
并且在程序功能完善之前,我们先对每一步功能直接在程序中输入,不考虑程序使用时的菜单,选项等步骤。这便于我们在写单独某一项功能的代码时,出现错误便于调试查找错误。

//"test.c"//我们在这里先将需要的功能函数写上,再在"list.c"中逐渐完善,
//最后再对这些代码进行“排版”

将每一项功能放在一个test();中,一一测试,节省时间,也更快捷。
设计函数中的参数时,注意:0传值传址的区别,以及其他参数的设计。
比如:增的设计中,&s是将地址传给形参,可修改其中的元素;i是第几位元素;num是要添加上的数字。
假如i为4,num为9. 数组中的元素是{ 1, 1,4,5,6, 7,8,9 };,那么这段增的函数运行后的数组变为{ 1,1,4,5,9,6,7,8,9 };那么当i=0时,就是头插,当i等于sz时,就是尾插。
其他的函数可以同理。
还需注意:num的类型可以用宏定义,以便选择使用不同的数据类型。
因此 #define int SLDataType

#include "list.h"int main()
{SL s;int i = 0;SLDataType num = 0;//初始化顺序表SLInit(&s);		//了解传值和传址的区别//	//函数中中的pos,和num是方便理解,//	// 大家可以根据自己需求来修改//	//比如使用函数时直接(&s,0,3)这样//	//或者在函数中scanf等语句来修改pos和num的值//增-插入-头查-尾插-随机插入(查到才能插入)SLInsert(&s, i, num);//删-头删-尾删-随机删除(查到就能删除)SLErase(&s, i);//查SLFind(&s,i);//改-查到再改SLModify(&s, i, num);//销毁顺序表SLDestroy(&s);return 0;
}

5.lish.h

#pragma once#include <stdio.h>
#include <stdlib.h>
#include <assert.h>typedef int SLDataType;//num的数据类型// 顺序表的动态存储
typedef struct SeqList
{SLDataType* array; // 指向动态开辟的数组size_t size; // 有效数据个数size_t capacity; // 容量空间的大小
}SL;//初始化顺序表
void SLInit(SL* p);//销毁顺序表
void SLDestroy(SL* p);//增-插入-头查-尾插-随机插入
void SLInsert(SL* p,int pos, SLDataType num);//删-头删-尾删-随机删除
void SLErase(SL* p, int pos);//查
int SLFind(SL* p, SLDataType num);//改-查到再改
void SLModify(SL* p, int pos, SLDataType num);//打印-可供查看信息
void SLPrint(SL* p);

6.lish.c

线性表.png

#include "list.h"//初始化顺序表
void SLInit(SL* p) {p->array = (SLDataType*)malloc(sizeof(SLDataType) * 4);if (p->array == NULL){perror("malloc fail");return;}p->size = 0;p->capacity = 4;
}//增容
void SLCheckcapacity(SL* p)
{if ( p ->size == p->capacity){SLDataType* tmp = (SLDataType*)realloc(p->array,sizeof(SLDataType) * p->capacity * 2);if (tmp == NULL){perror("realloc fail");return;}p->array = tmp;p->capacity *= 2;}
}//增-插入-头查-尾插-随机插入
void SLInsert(SL* p, int pos, SLDataType num)
{assert(p);assert(0 <= pos && pos <= p->size);//先写一个插入后,后续元素要往后移动的程序//注意不要越界,因此要判断一个容量够不够存储SLCheckcapacity(p);for (int i = 0; i < p->size - pos; i++){p->array[p->size - i] = p->array[p->size - 1 - i];}p->array[pos] = num;p->size++;
}//删-头删-尾删-随机删除
void SLErase(SL* p, int pos)
{assert(p);assert(0 < pos && pos <= p->size);for (int i = pos; i < p->size-1; i++){p->array[i] = p->array[i+1];}if(p->size > 0)p->size--;
}//查
int SLFind(SL* p, SLDataType num)
{assert(p);for (int i = 0; i < p->size; i++){if (num == p->array[i])return i+1;}return -1;
}//改
void SLModify(SL* p, int pos, SLDataType num)
{assert(p);assert(0 < pos && pos <= p->size);p->array[pos] = num;
}//打印-可供查看信息
void SLPrint(SL* p) 
{assert(p);for (int i = 0; i < p->size; i++){printf("%d ", p->array[i]);}printf("\n");
}//销毁顺序表
void SLDestroy(SL* p)
{assert(p);free(p->array);p->array = NULL;p->size = 0;p->capacity = 0;
}

(三)完善代码

加上菜单等,循环等,让程序更完善。

(四)线性表的顺序存储结构的优缺点

优点:

  • 无须为表示表中元素之间的逻辑关系而增加额外的存储空间;
  • 可以快速地存取表中任一位置的元素。

缺点:

  • 插入和删除操作需要移动大量元素;
  • 当线性表长度变化较大时,难以确定存储空间的容量;
  • 造成存储空间的“碎片”。

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

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

相关文章

IP地址定位技术能精确到街道级别吗?

IP地址定位技术可以精确到街道级别&#xff0c;但这并不是普遍情况。IP地址定位的精度受到多种因素的影响&#xff0c;包括IP地址库的准确性、网络延迟、地理位置数据的更新频率等。此外&#xff0c;大多数网络用户都是使用动态IP上网&#xff0c;这也会增加定位的难度。 IP地址…

wordpress外贸独立站

WordPress外贸电商主题 简洁实用的wordpress外贸电商主题&#xff0c;适合做外贸跨境的电商公司官网使用。 https://www.jianzhanpress.com/?p5025 华强北面3C数码WordPress外贸模板 电脑周边、3C数码产品行业的官方网站使用&#xff0c;用WordPress外贸模板快速搭建外贸网…

jetson nano——编译安装cmake(全局+图文)

目录 1.安装openssl2.源码编译安装OpenSSL3.编译安装cmake3.1卸载旧版本的cmake3.2.下载源码3.3解压3.4进入解压后的目录3.5配置路径3.5.1指定openssl路径3.5.2配置路径 3.6编译3.7安装3.8编辑环境变量3.9确定是否成功安装 系统&#xff1a;jetson-nano-jp451-sd-card-image ub…

[JavaWeb玩耍日记]HTML+CSS+JS快速使用

目录 一.标签 二.指定css 三.css选择器 四.超链接 五.视频与排版 六.布局测试 七.布局居中 八.表格 九.表单 十.表单项 十一.JS引入与输出 十二.JS变量&#xff0c;循环&#xff0c;函数 十三.Array与字符串方法 十四.自定义对象与JSON 十五.BOM对象 十六.获取…

安泰功率放大器的应用领域介绍

随着现代科技的快速发展&#xff0c;功率放大器已经成为各种电子设备中不可或缺的组成部分。它可以将低功率的信号放大为高功率的信号&#xff0c;使得信号能够更远地传输&#xff0c;更好地驱动各种负载。因此&#xff0c;在许多领域中&#xff0c;功率放大器都扮演着重要角色…

Achronix以创新FPGA技术推动智能汽车与先进出行创新

全球领先的高性能现场可编程门阵列&#xff08;FPGA&#xff09;和嵌入式FPGA&#xff08;eFPGA&#xff09;半导体知识产权&#xff08;IP&#xff09;提供商Achronix Semiconductor公司宣布&#xff0c;该公司将参加由私募股权和风险投资公司Baird Capital举办的“Baird车技术…

Redis-基础篇

Redis是一个开源、高性能、内存键值存储数据库&#xff0c;由 Salvatore Sanfilippo&#xff08;网名antirez&#xff09;创建&#xff0c;并在BSD许可下发布。它不仅可以用作缓存系统来加速数据访问&#xff0c;还可以作为持久化的主数据存储系统或消息中间件使用。Redis因其数…

品牌与时间函数:在时间的长河中铸造品牌

品牌推广是一个与时间紧密相连的复杂过程。时间不仅是品牌推广的见证者&#xff0c;更是其推动者和塑造者。迅腾文化深刻理解品牌推广与时间之间的微妙关系&#xff0c;提出的“显”的原则&#xff0c;旨在通过巧妙的策略&#xff0c;使品牌在时间的流转中逐渐显现出其特别的魅…

windows下安装npm

windows下安装了多个node.js如何切换npm。 下载nvm 下载nvm地址&#xff1a;https://github.com/coreybutler/nvm-windows/releases 安装nvm 这个是nodejs的安装位置&#xff0c;如果没有nodejs文件夹就新建一个(后来发现他会自动生成一个快捷方式) 设置setting.txt 打开安装…

【漏洞复现】ShopXO任意文件读取漏洞

Nx01 产品简介 ShopXO是一套开源的企业级开源电子商务系统&#xff0c;包含PC、H5、微信小程序、支付宝小程序、百度小程序等多个终端&#xff0c;遵循Apache2开源协议发布&#xff0c;基于ThinkPHP5.1框架研发。该系统具有求实进取、创新专注、自主研发、国内领先企业级B2C电商…

rust多个mod文件引用和文件夹mod使用注意事项

如果mod文件都在同一级目录&#xff0c;则直接使用就可以&#xff0c;因为rust文件都是一个隐藏的mod&#xff0c;但是如果mod文件在另外一个目录下面&#xff0c;就需要在目录下面声明一个mod.rs文件&#xff0c;这样才能将那个目录识别为一个mod&#xff0c;可以在mod.rs里面…

《教育信息化论坛》是什么级别的期刊?知网收录吗?能评职称吗?

问题解答&#xff1a; 问&#xff1a;《教育信息化论坛》是什么级别的刊物&#xff1f; 答&#xff1a;省级 主管单位:中原大地传媒股份有限公司 主办单位:河南电子音像出版社有限公司 文心出版社有限公司 问&#xff1a;《教育信息化论坛》是学术期刊吗&#xff1f; 答…