数据结构——线性表

目录

1.线性表的定义

2.顺序表

2.1顺序表的定义

 2.2 顺序表的应用

2.2.1 顺序表的管理

(1) 顺序表的初始化

(2) 销毁顺序表

(3) 打印顺序表的值

(4)检查顺序表的容量

(5)尾插法

(6) 尾删法

(7) 头插法

(8) 头删法

(9) 测试

2.2.2 顺序表指定位置的插入和删除

(1)在pos位置插入x

(2) 删除pos位置的值

2.2.3 OJ练习题  

(1)27. 移除元素 - 力扣(LeetCode)

(2)88. 合并两个有序数组 - 力扣(LeetCode)


1.线性表的定义

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

         线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串。线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的, 线性表在物理上存储时,通常以数组和链式结构的形式存储。

2.顺序表

2.1顺序表的定义

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

顺序表一般可以分为:

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

顺序表采用数组储存,那我们定义的时候就需要定义一个数组,我们采用结构体储存这个结构。静态顺序表的大小是确定的,我们用一个常量N表示。下面给出代码:

 //静态顺序表
#define N 1000
typedef int SLDataType;struct SeqList
{SLDataType a[N];int size;//有效数据的个数
};

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

动态顺序表我们使用一个指针,指针指向数组,在使用的时候使用动态内存函数,动态开辟内存空间。下面给出代码:

// 动态顺序表
typedef int SLDataType;typedef struct SeqList
{SLDataType* a;   //指针指向空间int size;        // 存储有效数据个数int capacity;    // 空间大小
}SL;
 2.2 顺序表的应用

        实际应用中,由于静态顺序表的大小很难确定,小了不够用,大了浪费空间,所以我们大多时候采用动态顺序表,那么接下来我们就基于动态顺序表进行定义。

2.2.1 顺序表的管理

        我们给出一些顺序表的基本操作,增加数据,删除数据,改变数据,查看数据。

// 管理数据 -- 增删查改
void SLInit(SL* ps);
void SLDestroy(SL* ps);
void SLPrint(SL* ps);
void SLCheckCapacity(SL* ps);
(1) 顺序表的初始化

        我们在使用顺序表时候,首先要对顺序表进行初始化。此时我们传入的参数是结构体指针而不是结构体,是为了改变实参。我们为数组a动态开辟了4个SLDataType大小的空间,动态内存开辟不要忘记对开辟的空间进行检查。然后我们初始化此时的空间大小为4,数据使用的空间为0。代码如下:

//初始化顺序表 注意要传指针才能改变实参
void SLInit(SL* ps)
{//动态开辟内存ps->a = (SLDataType*)malloc(sizeof(SLDataType) * 4);if (ps->a == NULL){perror("malloc failed");exit(-1);//程序报错 直接退出//return;区分于return返回值}ps->size = 0;ps->capacity = 4;
}
(2) 销毁顺序表

        我们是动态开辟的空间,使用完了之后要对顺序表进行销毁。先释放空间,后别忘了对指针置空,防止野指针!代码如下:

//销毁顺序表
void SLDestroy(SL* ps)
{free(ps->a);ps->a = NULL;ps->capacity = ps->size = 0;
}
(3) 打印顺序表的值

        我们需要一个函数打印出此时顺序表里面的值,size是数组里的有效数据大小,所以我们只需要打印到size。代码如下:

//打印顺序表的值
void SLPrint(SL* ps)
{for (int i = 0; i < ps->size; i++){printf("%d ", ps->a[i]);}printf("\n");
}
(4)检查顺序表的容量

        我们初始化内存大小是4,如果我们此时要存8个数据,就会发生越界。所以我们定义一个函数检查此时顺序表的容量。我们分配的大小为现在大小的两倍,记得检查空间是否成功开辟,此时顺序表的容量就变为原来的两倍。在这里有个细节:我们用的是realloc,它生成的空间有两种不同的方法,忘记的大家可以看一下之前C语言进阶部分内存函数的知识。所以我们一开始把生成的空间用临时变量储存,最后在把临时变量赋给a。防止开辟失败导致内存泄漏。代码如下:

//检查顺序表的容量
void SLCheckCapacity(SL* ps)
{// 满了要扩容if (ps->size == ps->capacity){SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2 * (sizeof(SLDataType)));if (tmp == NULL){perror("realloc failed");exit(-1);}ps->a = tmp;ps->capacity *= 2;}
}
(5)尾插法

        我们先来了解什么是尾插法,尾插法就是把数据每次都插入顺序表最末尾的位置。那我们在插入前要先检查空间是否够用,然后只需要将数据放入有效数据末尾,增加有效数据长度即可。

// 尾插法
void SLPushBack(SL* ps, SLDataType x)
{SLCheckCapacity(ps);ps->a[ps->size] = x;ps->size++;
}
(6) 尾删法

        尾删法,从尾部一个一个删除数据,但这里我们需要检查有效数据的大小,如果它此时为0,那我们直接执行删除,下一次使用就会导致数组越界。所以我们需要进行一个断言。

//尾删法
void SLPopBack(SL* ps)
{assert(ps->size > 0);//ps->a[ps->size - 1] = 0;ps->size--;
}
(7) 头插法

        头插法就是从数组的前面插入值,我们先来看一下实现方法:

   

 

        我们用这种方法把值往后移动一位,要从后往前覆盖,不能从前往后,防止丢失值。空出开头位给插入数据,大家看懂的话可以尝试自己写一下代码,想一想循环的终止条件。

//头插法:从后往前覆盖值
void SLPushFront(SL* ps, SLDataType x)
{SLCheckCapacity(ps);// 挪动数据int end = ps->size - 1;while (end >= 0){ps->a[end + 1] = ps->a[end];--end;}ps->a[0] = x;ps->size++;
}
(8) 头删法

        头删法的思想和头插法类似,我们定义一个begin指针,只需要将后面的值往前覆盖,覆盖到最前面的值就好,还是注意循环的终止条件。

//头删法:从后往前覆盖
void SLPopFront(SL* ps)
{//注意检查size大小assert(ps->size > 0);int begin = 1;while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];++begin;}ps->size--;
}
(9) 测试
#include<stdio.h>#include"SeqList.h"void TestSeqList1()
{SL sl;SLInit(&sl);SLPushBack(&sl, 1);SLPushBack(&sl, 2);SLPushBack(&sl, 3);SLPushBack(&sl, 4);SLPushBack(&sl, 5);SLPushBack(&sl, 6);SLPushBack(&sl, 6);SLPushBack(&sl, 0);SLPushBack(&sl, 0);SLPrint(&sl);SLPopBack(&sl);SLPopBack(&sl);SLPrint(&sl);SLPopBack(&sl);SLPopBack(&sl);SLPopBack(&sl);SLPopBack(&sl);SLPopBack(&sl);SLPopBack(&sl);SLPopBack(&sl);//SLPopBack(&sl);//SLPopBack(&sl);/*SLPopBack(&sl);SLPopBack(&sl);SLPopBack(&sl);SLPopBack(&sl);*/SLPrint(&sl);SLPushBack(&sl, 1);SLPushBack(&sl, 2);SLPrint(&sl);SLDestroy(&sl);
}int main()
{TestSeqList1();return 0;
}

大家可以根据自己理解想一想测试函数输出的值是多少?看是否充分了解尾插数据插入位置。

void TestSeqList2()
{SL sl;SLInit(&sl);SLPushBack(&sl, 1);SLPushBack(&sl, 2);SLPushBack(&sl, 3);SLPushBack(&sl, 4);SLPushBack(&sl, 5);SLPrint(&sl);SLPushFront(&sl, 10);SLPushFront(&sl, 20);SLPushFront(&sl, 30);SLPushFront(&sl, 40);SLPrint(&sl);SLPopFront(&sl);SLPrint(&sl);
}int main()
{TestSeqList2();return 0;
}

大家可以根据自己理解想一想测试函数输出的值是多少?看是否充分了解头插数据插入位置。 

2.2.2 顺序表指定位置的插入和删除
(1)在pos位置插入x

        在pos位置处插入值x的思路有一些像头插,不过头插是第一个位置,那pos位置插入改变一下循环条件就可以解决,问题是要对pos位置进行限制,pos不能小于0,pos也不能大于size。

// 在pos位置插入x
void SLInsert(SL* ps, int pos, SLDataType x)
{assert(ps);assert(pos >= 0 && pos <= ps->size);SLCheckCapacity(ps);int end = ps->size - 1;while (end >= pos){ps->a[end + 1] = ps->a[end];--end;}ps->a[pos] = x;ps->size++;
}
(2) 删除pos位置的值

        删除pos位置的值,通过一个begin指针,实现从pos位置后面的值对前面的值进行覆盖。相当于头删的时候,pos值为0。代码实现原理如下:

// 删除pos位置的值
void SLErase(SL* ps, int pos)
{assert(ps);assert(pos >= 0 && pos < ps->size);int begin = pos + 1;while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];++begin;}ps->size--;
}
2.2.3 OJ练习题  
(1)27. 移除元素 - 力扣(LeetCode)

考虑到空间复杂度,这道题我们的思路是用两个指针对数组进行判断。一个src指针,一个dst指针,我们对src指向的值进行判断,若src指向的值不等于val,那我们就把值赋给dst,再把src++和dst++,最后返回数组的长度就是dst。我们来看一下演示步骤:

int removeElement(int* nums, int numsSize, int val) {int dst=0;int src=0;while(src<numsSize){if(nums[src]!=val){nums[dst++]=nums[src++];}else{src++;}}return dst;
}
(2)88. 合并两个有序数组 - 力扣(LeetCode)

我们先来了解什么是非递减序列:1 2 2 5 6这种序列就是非递减序列,递增序列:1 2 3 5 6,这种就是递增序列。接下来我们思考一下这道题目:要求两个非递减序列合并到大的序列后依旧为非递减序列。我们对两个数组定义两个指针,倒着比较将大的数插入。每个数组最后面的都是最大的数,放在最后就可以保证生成的数组还是非递减数组。代码如下:

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) {int end1=m-1,end2=n-1,end=m+n-1;while(end1>=0&&end2>=0){if(nums1[end1]>nums2[end2]){nums1[end--]=nums1[end1--];}else{nums1[end--]=nums2[end2--];}}while(end2>=0){nums1[end--]=nums2[end2--];}
}

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

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

相关文章

3.2 Windows驱动开发:内核CR3切换读写内存

CR3是一种控制寄存器&#xff0c;它是CPU中的一个专用寄存器&#xff0c;用于存储当前进程的页目录表的物理地址。在x86体系结构中&#xff0c;虚拟地址的翻译过程需要借助页表来完成。页表是由页目录表和页表组成的&#xff0c;页目录表存储了页表的物理地址&#xff0c;而页表…

【RTP】RTPSenderAudio::SendAudio

RTPSenderAudio 可以将一个opus帧封装为rtp包进行发送,以下是其过程:RTPSenderAudio::SendAudio :只需要提供payload部分 创建RtpPacketToSend 并写入各个部分 填充payload部分 sender 本身分配全session唯一的twcc序号 if (!rtp_sender_->

服务器连接github

https://zhuanlan.zhihu.com/p/543490354 比着这个一步步做就行。 https://blog.l0v0.com/posts/94ffdbdf.html 上传文件可以看这个 注意&#xff1a; 密钥ssh-keygen设置好之后&#xff0c;以后就不用每次输入账号密码才能访问了。 otherwise&#xff0c;每次要输入账号密码。…

【C++】PACS医学图像存储和传输系统源码带三维重建

PACS&#xff08;Picture Archiving and Communication System&#xff09;系统作为医学图像的存储和传输平台&#xff0c;为医生和患者提供了便捷高效的诊疗服务支持。近年来&#xff0c;三维重建技术在PACS系统中的应用越来越广泛。 三维后处理功能是临床数字技术中的重要组成…

OpenCV快速入门:相机标定——单目视觉和双目视觉

文章目录 前言一、相机标定的基本原理1.1 相机模型与坐标系1.1.1 相机模型1.1.2 坐标系 1.2 相机内参与外参1.2.1 内部参数1.2.2 外部参数 1.3 镜头畸变1.4 透视变换1.5 标定的重要性和应用场景 二、单目视觉2.1 单目视觉的原理2.1.1 单目视觉的原理2.1.2 单目视觉的公式2.1.3 …

nodejs+vue+python+PHP+微信小程序-健身俱乐部在线管理平台的设计与实现-安卓-计算机毕业设计

随着经济的发展、财富的累积&#xff0c;人们生活水平、生活质量大幅度提高&#xff0c;生活环境得到明显改善&#xff0c;但是竞争激烈、人们生活压力大、生活节奏快加上饮食习惯和生活方式不合理导致国内 亚健康人群逐年增多。统计数据表明当前我国亚健康人群比例已经超过了7…

基于ncurse实现的俄罗斯方块

1. 需求分析 方块的类型方块的变形方块的消除方块的存储方块的移动接受用户的输入 2. 概要设计 2.1 方块类型与变形 一共有七种&#xff0c;变换的方式如下。变换后的任意形状方块实际上可以存在一个4x4的矩阵中。 我们再压一下位&#xff0c;就可以存在16位中。 2.2 方块…

Transformer——decoder

上一篇文章&#xff0c;我们介绍了encoder&#xff0c;这篇文章我们将要介绍decoder Transformer-encoder decoder结构&#xff1a; 如果看过上一篇文章的同学&#xff0c;肯定对decoder的结构不陌生&#xff0c;从上面框中可以明显的看出&#xff1a; 每个Decoder Block有两个…

nodejs微信小程序+python+PHP-健身俱乐部在线管理平台的设计与实现-安卓-计算机毕业设计

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

在 STM32 上实现温度补偿和校正

本文介绍了如何在 STM32 微控制器上实现温度补偿和校正&#xff0c;以提高温度传感器的测量精度。首先&#xff0c;我们将简要介绍温度补偿和校正的原理和目的。然后&#xff0c;我们将详细讨论在 STM32 上实现温度补偿和校正的步骤和方法。同时&#xff0c;提供了一个简单的示…

[element-ui] el-dialog 中的内容没有预先加载,因此无法获得内部元素的ref 的解决方案

问题描述 在没有进行任何操作的时候&#xff0c;使用 this.$refs.xxxx 无法获取el-dialog中的内部元素&#xff0c;这个问题会导致很多bug. 官方解释&#xff0c;在open事件回调中进行&#xff0c;但是open()是弹窗打开时候的会调&#xff0c;有可能在此处获取的时候&#xff…

基于减法平均算法优化概率神经网络PNN的分类预测 - 附代码

基于减法平均算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于减法平均算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于减法平均优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…