数据结构-详细介绍线性表中的顺序表

embedded/2024/12/22 10:07:09/

目录

一. 线性表

二.顺序表

1.静态顺序表与动态顺序表

2.动态顺序表的接口实现

2.1顺序表初始化

2.2判断是否需要扩容

2.3顺序表指定位置插入

2.4顺序表头插

2.5顺序表尾插

2.6顺序表指定位置删除

2.7 顺序表头删

2.8 顺序表尾删

2.9顺序表查找

2.10 顺序表修改 

2.11 顺序表销毁

2.12顺序表打印

3. 顺序表的缺点

三.代码仓库


一. 线性表

1. 线性表(linear list)是n个具有相同特性的数据元素有限序列

2. 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...

3. 线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。


二.顺序表

1.静态顺序表与动态顺序表

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

2. 顺序表一般可以分为:

静态顺序表:使用定长数组存储元素。

#define N 10
typedef int SLDataType;
typedef struct SeqList
{SLDataType array[N]; //定长数组size_t size;         //有效数据个数
}SeqList;

动态顺序表:使用动态开辟的数组存储。

typedef int SLDataType;
typedef struct SeqList
{SLDataType* array; //指向动态开辟的数组size_t size;       //有效数据个数size_t capacity;   //空间容量
}SeqList;

2.动态顺序表的接口实现

1. 静态顺序表只适用于确定知道需要存多少数据的场景。

2. 静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。

3. 所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。

 

2.1顺序表初始化

将结构的每个成员初始化

void SeqListInit(SeqList* psl, size_t capacity)
{assert(psl);psl->array = (SLDataType*)malloc(sizeof(SeqList) * capacity);if (psl->array == NULL){perror("malloc");return;}psl->size = 0;psl->capacity = capacity;
}

 

2.2判断是否需要扩容

1.判断有效个数是否和容量相等

2.使用realloc进行扩容

void CheckCapacity(SeqList* psl)
{assert(psl);if (psl->size == psl->capacity){SLDataType* tmp = (SLDataType*)realloc(psl->array, sizeof(SLDataType) * psl->capacity * 2);if (tmp == NULL){perror(realloc);return;}psl->array = tmp;psl->capacity *= 2;}
}

 

2.3顺序表指定位置插入

1. 对pos进行范围判断。

1. 判断是否需要扩容。

2. 将pos后面的元素往后挪一位。

3. pos位置插入值。

4. 有效个数加一。

void SeqListInsert(SeqList* psl, size_t pos, SLDataType x)
{assert(psl);assert(pos >= 0 && pos <= psl->size);CheckCapacity(psl);size_t cur = psl->size;while (cur != pos){psl->array[cur] = psl->array[cur - 1];cur--;}psl->array[pos] = x;psl->size++;
}

 

2.4顺序表头插

方法1:

1. 判断是否需要扩容。

2. 将所有元素都往后移一位,留出第一个位置插入(如果头插之前没有元素,则直接插入即可)。

3. 有效个数加一。

 

void SeqListPushFront(SeqList* psl, SLDataType x)
{assert(psl);CheckCapacity(psl);int tmp = psl->size;while (tmp > 0) //当本身为空时,就不走这个循环{psl->array[tmp] = psl->array[tmp - 1];tmp--;}psl->array[0] = x;psl->size++;
}

方法2:复用SeqListInsert

void SeqListPushFront(SeqList* psl, SLDataType x)
{SeqListInsert(psl, 0, x);
}

2.5顺序表尾插

1. 插入前判断是否需要增容。

2. size作为下标正好是最后一个元素的后一位。

 

void SeqListPushBack(SeqList* psl, SLDataType x)
{assert(psl);CheckCapacity(psl);psl->array[psl->size++] = x;
}

方法2:复用SeqListInsert

void SeqListPushBack(SeqList* psl, SLDataType x)
{assert(psl);SeqListInsert(psl, psl->size, x);
}

2.6顺序表指定位置删除

1. 判断pos是否合法。

2. 将pos后面的元素往前覆盖一位。

3. 有效个数减一。

 

void SeqListErase(SeqList* psl, size_t pos)
{assert(psl);assert(pos >= 0 && pos < psl->size);int cur = pos;while (cur < psl->size - 1){psl->array[cur] = psl->array[cur + 1];cur++;}psl->size--;
}

2.7 顺序表头删

方法1:

1. 判断有效个数是否为0,为0不用删。

2. 将后面的与元素往前覆盖一位。

3. 有效元素个数减一。

void SeqListPopFront(SeqList* psl)
{assert(psl);assert(psl->size);size_t cur = 0;while (cur < psl->size - 1){psl->array[cur] = psl->array[cur + 1];cur++;}psl->size--;
}

方法2:复用SeqListErase

void SeqListPopFront(SeqList* psl)
{assert(psl);SeqListErase(psl, 0);
}

2.8 顺序表尾删

方法1:

1. 判断size,size如果为0就不能删。

2. 删除尾部元素直接将size减减即可。

void SeqListPopBack(SeqList* psl)
{assert(psl);assert(psl->size);psl->size--;
}

方法2:复用SeqListErase

void SeqListPopBack(SeqList* psl)
{assert(psl);SeqListErase(psl, psl->size - 1);
}

2.9顺序表查找

1. 遍历一遍进行比较。

2. 找到返回下标,否则返回-1。

 

int SeqListFind(SeqList* psl, SLDataType x)
{assert(psl);for (size_t i = 0; i < psl->size; i++){if (psl->array[i] == x) return i;}return -1;
}

2.10 顺序表修改 

1. 对pos进行范围判断。

2. 将pos作为下标进行修改。

 

void SeqListModify(SeqList* psl, size_t pos, SLDataType x)
{assert(psl);assert(pos >= 0 && pos < psl->size);psl->array[pos] = x;
}

2.11 顺序表销毁

1. 销毁时需要释放空间,指针置空。

2. 有效个数和容量置0。

 

void SeqListDestory(SeqList* psl)
{assert(psl);free(psl->array);psl->array = NULL;psl->capacity = 0;psl->size = 0;
}

2.12顺序表打印

遍历数字打印

void SeqListPrint(SeqList* psl)
{assert(psl);for (int i = 0; i < psl->size; i++) printf("%d ", psl->array[i]);printf("\n");
}

 

3. 顺序表的缺点

1. 中间/头部的插入删除,时间复杂度为O(N)。

2. 增容需要申请新空间,拷贝数据,释放旧空间,会有不小的消耗。

3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。

 


三.代码仓库

 gitee/jimmywang16/learn_1


http://www.ppmy.cn/embedded/125392.html

相关文章

VUE 开发——Vue学习(二)

一、watch侦听器 作用&#xff1a;监视数据变化&#xff0c;执行一些业务逻辑或异步操作 简单写法 <div id"app"><textarea v-model"words"></textarea></div><script>const app new Vue({el:#app,data: {words: },watch…

FOC电机驱动开发踩坑记录

关键技术 SVPWM电机磁场控制电流采样park变换和Clark变换滑膜观测器&#xff08;无感FOC&#xff09; SVPWM电机磁场控制 SVPWM主要思想是通过精确的对UVW三相电流的分时控制&#xff0c;来控制转子的合成力矩&#xff0c;达到目标方向&#xff0c;常用的是6分区的设计&…

小北的技术博客:探索华为昇腾CANN训练营与AI技术创新——Ascend C算子开发能力认证考试(中级)

前言 哈喽哈喽&#xff0c;这里是zyll~,北浊.&#xff08;大家可以亲切的呼唤我叫小北&#xff09;智慧龙阁的创始人&#xff0c;一个在大数据和全站领域不断深耕的技术创作者。今天&#xff0c;我想和大家分享一些关于华为昇腾CANN训练营以及AI技术创新的最新资讯和实践经验~&…

LeetCode Hot100 | Day2 | 二叉树:二叉树的中序遍历二叉树的最大深度

LeetCode Hot100 | Day2 | 二叉树&#xff1a;二叉树的中序遍历&&二叉树的最大深度 注&#xff1a;和之前写过题解的部分且能够一遍写出来的不再写题解&#xff08;可以写写注意点&#xff09; 94.二叉树的中序遍历 94. 二叉树的中序遍历 - 力扣&#xff08;LeetCod…

Python网络编程:开启你的网络之旅

引言 你有没有想过&#xff0c;为什么我们能在几秒钟内从世界的另一端获取信息&#xff1f;这背后&#xff0c;正是网络编程的魔力&#xff01;在这个数字化的时代&#xff0c;掌握网络编程不仅能让你在技术上游刃有余&#xff0c;还能为你的职业生涯增添一笔亮丽的色彩。今天…

转型AI产品经理需要掌握的硬知识、经理能力模型和常见AI概念梳理

近几年&#xff0c;从亚马逊&#xff0c; Facebook&#xff0c;到谷歌&#xff0c;微软&#xff0c;再到国内的BAT&#xff0c;全球最具影响力的技术公司都将目光转向了人工智能&#xff08; AI &#xff09;。2016年 AlphaGo 战胜李世石&#xff0c;把公众的目光也聚集到了人工…

实战OpenCV之视频处理

基础入门 视频是由一系列连续的图像帧组成的&#xff0c;这些帧按照一定的速率连续播放&#xff0c;从而形成动态画面。与视频相关的主要参数有&#xff1a;分辨率、帧率、码率、编解码器、帧类型、文件格式等&#xff0c;下面分别进行介绍。 1、帧率。表示每秒显示的图像帧数&…

dba_free_space 视图查询慢 X$KTFBUE

1.监控程序 dba_free_space 视图查询慢&#xff0c;访问基表X$KTFBUE时间较长&#xff0c;且多为单块读db file sequential read。 SQL> set linesize 500 pagesize 50000 long 999999 longchunksize 999999 SQL> select dbms_sqltune.report_sql_monitor(sql_id > 4p…