线性表☞顺序表篇(7000字细致入微讲解)
个人主页:欢迎大家光临——>沙漠下的胡杨
各位大帅哥,大漂亮
如果觉得文章对自己有帮助
可以一键三连支持博主
你的每一分关心都是我坚持的动力
☄: 本期重点:线性表中的顺序表
希望大家每天都心情愉悦的学习工作。
什么是线性表?
什么是顺序表呢?
1.创建多文件项目
2.创建结构体
3.初始化数组
4.开辟动态空间 (增容)
5. 顺序表尾插
6. 顺序表的尾删
7.顺序表的头插
8.顺序表的头删
9.任意位置插入
10。删除任意位置
11,顺序表的查找
12.顺序表的数据修改
13.补充下删除和修改部分
14 头删尾删和头插尾插的优化
16.free开辟的空间和打印
17:关于整体代码
Seqlist.h文件
Seqlist.c文件
18:关于所用的知识:
下期预告:
什么是线性表?
线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使 用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的, 线性表在物理上存储时,通常以数组和链式结构的形式存储。
什么是顺序表呢?
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存 储。在数组上完成数据的增删查改。 顺序表一般可以分为:
1. 静态顺序表:使用定长数组存储元素。(长度固定)
2. 动态顺序表:使用动态开辟的数组存储。(可以扩容)
1.创建多文件项目
我们要通过多文件实现顺序表。
要有个头文件,和函数实现的 .c 文件 和 测试的源文件。
其中,头文件中要防止头文件重复包含,和头文件的引用。
2.创建结构体
我们要创建一个结构体来存放和进行顺序表相关操作。
typedef int SLdataType;typedef struct Seqlist {SLdataType *a;int size;int capicity; }SL;
我们创建了结构体,并且进行结构体的重命名,
然后我们要进行使用动态开辟的内存,所以我们要有一个指针变量,存放动态开辟的数组.
接着我们还有有已经存放元素的个数,和实际的容量大小。
最后,我们要考虑我们存什么数组呢?是整形,字符,浮点?这些不确定所以我们要把类型在进行重定义下,是为了我们可以更方便的维护数组。
3.初始化数组
我们有数组了,那么首先就要进行数组的初始化。
void SLInit(SL* ps) {assert(ps);ps->a = NULL;ps->capicity = ps->size = 0; }
我们要知道函数的声明要放入头文件(后续不在赘述),而函数的实现要放到 .c 文件中。
其次我们要进行函数的 "预防式" 编程,就是要进行判断传入函数指针的 "合法性"。
4.开辟动态空间 (增容)
我们最重要的动态的数组还没有呢?
我们要进行开辟,那么通过malloc开辟还是其他方式呢?
malloc开辟之后还要考虑增容问题,那么我们直接用realloc开辟不是更好。
所以我们这样开辟:
void SLCheckCapaticy(SL *ps) {assert(ps);if (ps->size == ps->capicity){//使用双目操作符让增容和初始化一个realloc函数实现。int newCapicity = ps->capicity == 0 ? 4 : 2 * (ps->capicity);SLdataType * tmp = (SLdataType *)realloc(ps->a, sizeof(SLdataType)*newCapicity);if (NULL == tmp){perror("realloc:");exit(-1);}ps->a = tmp;ps->capicity = newCapicity;} }
这样就可以用一个函数来实现开辟空间和增容的过程。
5. 顺序表尾插
尾插函数的实现比较简单,但是有一点要注意,就是判断否要增容。
void SLPushBack(SL* ps, SLdataType x) {assert(ps);SLCheckCapaticy(ps);ps->a[ps->size] = x;ps->size++; }
先判断函数的指针是否为空,在判断是否要增容,最后直接放数据就好啦。
6. 顺序表的尾删
尾删时,我们需要把删除的值置为 0 或者 -1吗?
答案是不需要,因为如果数据本来就是0 或 1呢,那么不就没有变吗?
所以我们只需要把结构体中的元素个数进行 -1 就可以了。
void SLPopBack(SL *ps) {assert(ps);assert(ps->size);ps->size--;}
7.顺序表的头插
顺序表的头插,就是在下标为 0 位置处进行写入,首先我们应该把 下标为 0 到下标为size 数
据向后移动一个数据大小的空间,把下标为 0 的空间腾出来。所以我们要进行数据的移动,
并且,我们要把数据从后向前的进行向后移动。
我们先创建一个变量作为下标,
这个下标不能够越界,并且要访问到0~size-1的元素,这就是循环条件。
然后就是不能越界,还要考虑扩容的问题。
最后放入元素,size++,就可以了。
void SLPushFront(SL *ps, SLdataType x) {assert(ps);SLCheckCapaticy(ps);int end = ps->size - 1;while (end >= 0){ps->a[end+1] = ps->a[end];end--;}ps->a[0] = x;ps->size++;}
8.顺序表的头删
头删和头插很像,但是有点不一样,限制条件更多了。
首先也要判断指针是否为空。
判断元素个数是否大于等于 0(也用assert进行断言)
头删只需要进行元素覆盖,不需要改元素。
移动元素进行覆盖。(元素是0到size-1,防止向前越界,限制条件为 1到 szie -1)
void SLPopFront(SL *ps) {assert(ps);assert(ps->size);int begin = 1;while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];begin++;}ps->size--;}
9.任意位置插入
任意位置插入的参数要多一个下标。
首先我们要判断指针和下标是否合法。
其次要考虑是否会越界,要进行扩容。
然后进行数据移动,限制和头插类似。(pos 到 size -1,实际访问pos到size)
最后放数据,size++
void SLInsert(SL* ps, int pos, SLdataType x) {assert(ps);assert(pos >= 0 && pos <= ps->size);SLCheckCapaticy(ps);int end = ps->size - 1;while (end >= pos){ps->a[end + 1] = ps->a[end];end--;}ps->a[pos] = x;ps->size++;}
10。删除任意位置
删除任意位置和插入的参数一样。
不需要考虑扩容,但是要考虑向前越界
数据移动:限制条件是 (pos 到 size-1,实际访问pos 到size)
最后把size--即可。
void SLErase(SL *ps, int pos) {assert(ps);assert(pos >= 0 && pos < ps->size);int begin = pos;while (begin < ps->size-1){ps->a[begin] = ps->a[begin+1];begin++;}ps->size--; }
11,顺序表的查找
查找的代码很简单,只需要遍历进行查找就可以啦。
需要注意的是返回的是找到数据的下标。
int SLFind(SL *ps, SLdataType x) {assert(ps);for (int i = 0; i < ps->size; i++){if (ps->a[i] == x){return i;}}return -1; }
12.顺序表的数据修改
修改也很简单,我们直接进行数据的覆盖即可。
需要注意的是下标的限制条件。1
void SLModify(SL *ps, int pos, SLdataType x) {assert(ps);assert(pos >= 0 && pos < ps->size);ps->a[pos] = x; }
13.补充下删除和修改部分
我们进行顺序表的查找和修改时,在进行数据的输入时,可以封装成函数。
有一点要注意的是,查找函数的返回值是可以作为判断的条件,以及可以作为链式访问的。
void Find(SL *ps)//查找相关的函数 {printf("请输入要查找的数据:");int a = 0;scanf("%d", &a);if (SLFind(ps, a) >= 0){printf("找到了,下标是:%d\n", SLFind(ps, a));SLPrint(ps);}else{printf("找不到\n");} }void Modify(SL *ps)//修改相关的函数 {printf("要查找的数据和要替换的数据:");int x = 0;int y = 0;scanf("%d%d", &x, &y);if (SLFind(ps, x) >= 0){SLModify(ps, SLFind(ps, x), y);printf("修改成功\n");SLPrint(ps);}else{printf("没找到:%d\n", x);} }
14 头删尾删和头插尾插的优化
我们已经写过了任意位置插入,那么我们是不是可以把头插尾插和头删和尾删进行下优化。
头插:
void SLPushFront(SL *ps, SLdataType x) {//assert(ps);//SLCheckCapaticy(ps);//int end = ps->size - 1;//while (end >= 0)//{// ps->a[end+1] = ps->a[end];// end--;//}//ps->a[0] = x;//ps->size++;SLInsert(ps, 0, x);//从0下标插入 }
尾插:
void SLPushBack(SL* ps, SLdataType x) {assert(ps);SLCheckCapaticy(ps);ps->a[ps->size] = x;ps->size++;//SLInsert(ps, ps->size, x);//从size位置插入,不会越界 }
头删:
void SLPopFront(SL *ps) {assert(ps);assert(ps->size);int begin = 1;while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];begin++;}ps->size--;//SLErase(ps, 0);//从0下标开始删 }
尾删:
void SLPopBack(SL *ps) {assert(ps);assert(ps->size);ps->size--;//SLErase(ps, ps->size - 1);//删除size-1位置的数据 }
这就是代码的可复用性。
16.free开辟的空间和打印
都没啥说的:
void SLPrint(SL *ps) {assert(ps);for (int i = 0; i < ps->size; i++){printf("%d ", ps->a[i]);}printf(" %d", ps->size);printf("\n"); }
void SLDestory(SL *ps) {assert(ps);if (ps->a != NULL){free(ps->a);ps->a = NULL;ps->capicity = ps->size = 0;} }
17:关于整体代码
Seqlist.h文件
#pragma once #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <assert.h>typedef int SLdataType;typedef struct Seqlist {SLdataType *a;int size;int capicity; }SL;void SLInit(SL* ps);//初始化void SLCheckCapaticy(SL *ps);//增容void SLPrint(SL *ps);//打印void SLDestory(SL *ps);//free空间void SLPushBack(SL* ps,SLdataType x);//尾插void SLPopBack(SL *ps);//尾删void SLPushFront(SL *ps,SLdataType x);//头插void SLPopFront(SL *ps);//头删void SLInsert(SL* ps, int pos, SLdataType x);//任意位置插入void SLErase(SL *ps, int pos);//任意位置删除int SLFind(SL *ps, SLdataType x);//查找 void Find(SL *ps);void SLModify(SL *ps, int pos, SLdataType x);//修改 void Modify(SL *ps);
Seqlist.c文件
#include "Seqlist.h"void SLPrint(SL *ps) {assert(ps);for (int i = 0; i < ps->size; i++){printf("%d ", ps->a[i]);}printf(" %d", ps->size);printf("\n"); }void SLInit(SL* ps) {assert(ps);ps->a = NULL;ps->capicity = ps->size = 0; }void SLCheckCapaticy(SL *ps) {assert(ps);if (ps->size == ps->capicity){int newCapicity = ps->capicity == 0 ? 4 : 2 * (ps->capicity);SLdataType * tmp = (SLdataType *)realloc(ps->a, sizeof(SLdataType)*newCapicity);if (NULL == tmp){perror("realloc:");exit(-1);}ps->a = tmp;ps->capicity = newCapicity;} }void SLPushBack(SL* ps, SLdataType x) {assert(ps);SLCheckCapaticy(ps);ps->a[ps->size] = x;ps->size++;//SLInsert(ps, ps->size, x); }void SLPushFront(SL *ps, SLdataType x) {//assert(ps);//SLCheckCapaticy(ps);//int end = ps->size - 1;//while (end >= 0)//{// ps->a[end+1] = ps->a[end];// end--;//}//ps->a[0] = x;//ps->size++;SLInsert(ps, 0, x); }void SLPopBack(SL *ps) {assert(ps);assert(ps->size);ps->size--;//SLErase(ps, ps->size - 1); }void SLPopFront(SL *ps) {assert(ps);assert(ps->size);int begin = 1;while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];begin++;}ps->size--;//SLErase(ps, 0); }void SLDestory(SL *ps) {assert(ps);if (ps->a != NULL){free(ps->a);ps->a = NULL;ps->capicity = ps->size = 0;} }void SLInsert(SL* ps, int pos, SLdataType x) {assert(ps);assert(pos >= 0 && pos <= ps->size);SLCheckCapaticy(ps);int end = ps->size - 1;while (end >= pos){ps->a[end + 1] = ps->a[end];end--;}ps->a[pos] = x;ps->size++;}void SLErase(SL *ps, int pos) {assert(ps);assert(pos >= 0 && pos < ps->size);int begin = pos;while (begin < ps->size-1){ps->a[begin] = ps->a[begin+1];begin++;}ps->size--; }int SLFind(SL *ps, SLdataType x) {assert(ps);for (int i = 0; i < ps->size; i++){if (ps->a[i] == x){return i;}}return -1; }void SLModify(SL *ps, int pos, SLdataType x) {assert(ps);assert(pos >= 0 && pos < ps->size);ps->a[pos] = x; }
18:关于所用的知识:
下面知识不太清楚的兄弟们,可以点击下面的链接,都是小编自己撰写的,欢迎关顾~!
指针相关的知识----->指针知识
内存管理相关知识讲解------>内存管理
结构体相关知识------->结构体知识
下期预告:
下期讲解函数栈帧的调用
下期憋个大的~!~!~!
线性表☞顺序表篇(7000字细致入微讲解)相关推荐
- rsa算法c语言实现_数据结构与算法之线性表-顺序表实现(C语言版本)
原文托管在Github: https://github.com/shellhub/blog/issues/52 数据结构与算法之线性表-顺序表实现(C语言版本) 前言 数据结构与算法是一个程序员必备的 ...
- 线性表-顺序表的基本操作
线性表的定义和特点 线性表:由n(n≥0)个数据特性相同的元素构成的有限序列 线性表中元素的个数n(n≥0)称为线性表的长度 空表:n=0 对于非空的线性表或线性结构,特点为: 存在唯一的一个被称作& ...
- 线性表→顺序表→链表 逐个击破
一. 线性表 1. 前言 线性表,全名为线性存储结构.使用线性表存储数据的方式可以这样理解,即 " 把所有(一对一逻辑关系的)数据用一根线儿串起来,再存储到物理空间中 ".这根线有 ...
- 线性表---顺序表链表
一.线性表 1.线性表中的元素是一对一的关系,除了第一个与最后一个元素之外其他数据元素都是首尾相连的. 如果是一对多就用树来表示,如果是多对多就用网状来表示. 2.线性表的两种存储结构 顺序表:用顺序 ...
- 线性表----顺序表
线性表的定义 线性表是具有相同数据类型的n个数据元素的有限序列, 逻辑特性 除第一个元素外,每个元素只有一个前驱,除最后一个元素外,每个元素都有一个后继 物理结构 线性表的存储结构有顺序存储结构和链式 ...
- 复习:线性表——顺序表
线性表:相同特性的数据元素的一个有限序列. 线性表的长度:n 序列中所含元素个数 空表:不包含任何元素 前驱:ai-1是ai的前驱 后继:ai+1是ai的后继 表头元素:a1 表尾元素:an 线性表 ...
- 线性表—顺序表-顺序表基本运算的实现
基本运算--初始化线性表 lintList 目标是构造出一个空的线性表 分配空间后,将length成员设置为0 对L的作用会传递回去 基本运算--销毁线性表 DestroyList C free() ...
- 线性表顺序表模板 纯本人手工创造
/* ***********************************************Author :mubaixuCreated Time :2015-12-08 20:45:05Fi ...
- 数据结构一线性表 (顺序表、单链表、双链表)
版权声明:本文为openXu原创文章[openXu的博客],未经博主允许不得以任何形式转载 文章目录 1.线性表及其逻辑结构 1.1 线性表的定义 1.2 线性表的抽象数据类型描述 2.线性表的顺序存 ...
最新文章
- 吓尿了!手机充完电不拔充电器后果这么严重
- 如何使用Java与Mysql进行数据交互
- esp32外部中断_玩转 ESP32 + Arduino (四) 电容按键 霍尔传感器 外部中断 延时 脉冲检测...
- 原码、反码、补码、移码的表示
- DOS 命令、必会的 10个 DOS 命令
- -9 逆序输出一个整数的各位数字_逆序对个数(归并排序)
- 剑指offer(21)栈的压入、弹出序列
- (转)GitHub 被微软收购后的 52 天,改版并放弃了 jQuery!
- php防伪溯源x系统_区块链溯源防伪追溯系统开发解决方案
- when-to-use-rebuild-vs-coalesce-vs-shrink
- [POJ3233] Matrix Power Series(矩阵快速幂)
- ubuntu下tftp服务器环境搭建
- 服务器内存条和普通内存条性能,科技知识:服务器内存条和普通内存条区别
- 语义分割CCNet-Criss Cross Network论文中注意力机制Criss Cross Attention模块的tensorflow代码实现
- mysql为何不建议使用外键
- Generalizing Surrogate-Assisted Evolutionary Computation
- 求一个n阶矩阵的转置矩阵
- 【转】ACM比赛经验
- WIN7 嵌入式系统安装教程 Windows Embedded Standard 2011 安装
- 数据分析综述:一文带你详细了解自动驾驶技术
热门文章
- 开发传感器应用的步骤
- [C语言]加减乘除训练系统
- AAAI 2021最佳论文 Informer
- ormlite android,如何使用ormLite在android中的现有实体中添加新字段?
- 在 Ubuntu 16.04 中 安装为知笔记
- java modbus lrc,C#实现modbus基于ASCII的LRC校验
- kafka-stream官方文档例子解析+springboot集成
- CFI与物理层峰值速率的关系
- 计算机晚会安排,计算机学院举办2018届毕业生“计忆拾光”主题晚会
- Python爬虫设计之职业社交网站——脉脉