文章目录

  • 一、什么是线性表?
  • 二、什么是顺序表
  • 三、顺序表的实现
    • 1.顺序表的接口
    • 2.每个接口的实现
    • 3.测试程序
    • 3.Java版本
  • 总结

一、什么是线性表?

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

二、什么是顺序表

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
顺序表一般可以分为:
1.静态顺序表:就是存储空间固定,如果空间被数据放满了,此时就不能再插入数据了

2.动态顺序表:存储空间不固定,可以增容

三、顺序表的实现

1.顺序表的接口

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

代码如下:

//顺序表中存储的数据类型为进行重命名
//为什么要重命名?
//因为如果以后想将存储数据的内容改为char或者double等其他类型的话,只需在这里该一次就可以,在之前的栈和队列我们已经说过了,下次就不说了---^_^
//而不必代码中的每一处都改,减少了不必要的麻烦,提高了代码的可读性
typedef int SQDataType;typedef struct SeqList
{SQDataType* a;//指向顺序表的指针int capacity;//顺序表的容量int size;//实际在顺序表中已经存储数据的个数
}SL;//顺序表的初始化
void SeqListInit(SL* ps);//
//检查容量是否已满
void SeqListCheckCapacity(SL* ps);//
//打印顺序表中的数据
void SeqListPrint(SL* ps);//
//尾插
void SeqListPushBack(SL* ps, SQDataType x);//
//尾删
void SeqListPopBack(SL* ps);//
//头插
void SeqListPushFront(SL* ps, SQDataType x);
//头删
void SeqListPopFront(SL* ps);
//顺序表的摧毁
void SeqListDestory(SL* ps);//
//随机插入
void SeqListInsert(SL* ps, size_t pos, SQDataType x);
//随机删除
void SeqListErase(SL* ps, size_t pos);
//在顺便表中找出一次出现x的下标,如果没有就返回-1
int SeqListFind(SL* ps, SQDataType x);
//修改下标为pos的值
void SeqListModify(SL* ps, size_t pos, SQDataType x);

2.每个接口的实现

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

//顺序表的打印
void SeqListPrint(SL* ps)
{assert(ps && ps->a);//断言ps是否合法(是否为NULL)并且断言ps->a(指向顺序表的指针)是否合法for (int i = 0; i < ps->size; i++)//从下标为0处开始打印数据,直到下标为size-1(最后一个数据)处为止{printf("%d ",ps->a[i]);}printf("\n");
}
//顺序表的摧毁
void SeqListDestory(SL* ps)
{assert(ps && ps->a);free(ps->a);ps->a = NULL;//释放后要将指针置NULL,防止被误操作(对已经被释放的空间操作)ps->capacity = ps->size = 0;//空间已经被释放了,所以capacity和size也要置0
}
//顺序表的初始化
void SeqListInit(SL* ps)
{assert(ps);ps->a = NULL;ps->capacity = ps->size = 0;
}
//检查容量是否已满
void SeqListCheckCapacity(SL* ps)//下面的头插,尾插等都需要调这个接口来检查是否需要扩容
{assert(ps);if (ps->capacity == ps->size)//当capacity和size相等时需要扩容,此时有两种情况{int NewCapacity = ps->capacity == 0 ? 4 : 2*ps->capacity;//当capacity为0时,表示此时是指针a指向的是NULL,直接给4个容量。//当capacity不为0时,直接扩容原来的两倍SQDataType* tmp = (SQDataType*)realloc(ps->a, NewCapacity*sizeof(SQDataType));//扩容//这里用一个类型为SQDataType*的指针接受realloc的返回值,如果不这么做可能造成内存泄漏,因为如果扩容失败,realloc将返回NULL//类似于ps->a=NULL,这样就会导致指针a也为NULL,原来a指向的空间就无法找到if (!tmp)//如果tmp为NULL,表示扩容失败,给出提示信息,异常终止程序->exit(-1){printf("relloc fail\n");exit(-1);}else{ps->a = tmp;//成功的话就将tmp赋给aps->capacity = NewCapacity;//容量也进行更新}}
}
//尾插
void SeqListPushBack(SL* ps,SQDataType x)
{assert(ps);SeqListCheckCapacity(ps);//先检查容量是否满了,满了就进行扩容ps->a[ps->size++] = x;//因为前面已经检查了capacity,所以直接插入数据//这里也等价于ps->a[ps->size] = x;//           ps->size++;
}
//尾删
void SeqListPopBack(SL* ps)
{assert(ps && ps->a);assert(ps->size > 0);//断言顺序表中是否有数据,如果有才进行Pop,所有的Pop接口都需要这么做ps->size--;//不必担心顺序表里的数据,因为在下一次尾插或者头插时,会将后面的数据覆盖
}
//头插
void SeqListPushFront(SL* ps, SQDataType x)
{assert(ps);SeqListCheckCapacity(ps);int end = ps->size - 1;//end就表示最后一个元素的下标位置while (end >= 0)//因为是头插,所以需要从前往后挪动数据,下面的头删,和随机删除,随机插入都需要挪动数据{ps->a[end + 1] = ps->a[end];end--;}ps->a[0] = x;//数据挪动完成,第一个位置就相当于空,所以就可以用来存储xps->size++;
}
//头删
void SeqListPopFront(SL* ps)
{assert(ps && ps->a);assert(ps->size > 0);int begin = 1;while (begin < ps->size)//这里依然是挪动数据,不过与前面不同的是,这里是从后往前挪动数据{ps->a[begin - 1] = ps->a[begin];//每次都将后一个数据挪到前一个位置begin++;}ps->size--;
}
//在顺便表中找出一次出现x的下标,如果没有就返回-1
int SeqListFind(SL* ps, SQDataType x)
{assert(ps && ps->a);for (int i = 0; i < ps->size; i++)//从下标为0开始遍历整个顺序表{if (ps->a[i] == x){return i;//如果找到了与x相等的数,就返回这个数的下标,不过这里只能返回第一个//换句话说,如果顺序表出现了多个与x相等的值,只返回第一个与x相等的数的下标,因为我们是从下标为0开始找的}}return -1;//如果找不到,就返回1,至于为什么返回1,众所周知,数组的下标不可能为负数,也可以返回其他负数,所以负数代表没找到
}
//在pos的位置插入
void SeqListInsert(SL* ps, size_t pos, SQDataType x)//size_t pos表示想插入的下标位置
{assert(ps && ps->a);assert(pos >= 0 && pos <= ps->size);//这里与前面的有所不同,主要是需要判断pos(下标位置)是否合法SeqListCheckCapacity(ps);size_t end = ps->size;while (end > pos){ps->a[end] = ps->a[end - 1];//依旧是挪动数据,从前往后挪end--;}ps->a[pos] = x;//挪动完后,pos的位置相当于空,此时就用来存放xps->size++;
}
//删除pos位置的值
void SeqListErase(SL* ps, size_t pos)
{assert(ps && ps->a);assert(pos >= 0 && pos < ps->size);//与前面的SeqListInsert是一样的原因int begin = pos + 1;while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];//从后往前挪动数据begin++;}ps->size--;
}
//修改pos位置的值
void SeqListModify(SL* ps, size_t pos, SQDataType x)
{assert(ps && ps->a);assert(pos >= 0 && pos < ps->size);//修改数据也要判断pos是否合法ps->a[pos] = x;//将位置为pos的数据修改为x
}

下面我们将用画图的方式来分析头插、头删、尾插、尾删等接口:

3.测试程序

代码如下:

void test()
{SL s;SeqListInit(&s);SeqListPushBack(&s, 1);SeqListPushBack(&s, 2);SeqListPushBack(&s, 3);SeqListPrint(&s);SeqListPopBack(&s);SeqListPrint(&s);SeqListPushFront(&s, 4);SeqListPushFront(&s, 5);SeqListPrint(&s);SeqListInsert(&s, 2, 7);SeqListPrint(&s);SeqListErase(&s, 2);SeqListPrint(&s);SeqListDestory(&s);
}int main()
{test();return 0;
}

3.Java版本

import java.util.Arrays;public class MyArrayList {public int[] elem;//数组private int usedSize;//有效数据的个数public static final int intCapacity = 10;//初始容量public MyArrayList() {this.elem = new int[intCapacity];this.usedSize = 0;}//判满private boolean isFull() {return this.usedSize == this.elem.length;}//判空private boolean isEmpty() {return this.usedSize == 0;}//检查pos合法性private void checkPos(int pos) {if(pos < 0 || pos >usedSize) {throw new RuntimeException("pos不合法");//抛出异常}}//增容private void increaseCapacity() {this.elem = Arrays.copyOf(this.elem, this.elem.length*2);}//打印顺序表public void display() {for (int i = 0; i < usedSize; i++) {System.out.print(elem[i]+" ");}}//在pos位置新增元素public void add(int pos, int data) {if(isFull()) {increaseCapacity();}checkPos(pos);for(int i = usedSize - 1; i >= pos; i--) {this.elem[i+1] = this.elem[i];}this.elem[pos] = data;this.usedSize++;}//获取pos位置的元素public int getPos(int pos) {if(isEmpty()) {throw new RuntimeException("elem为空");}checkPos(pos);return this.elem[pos];}//查找某个元素第一次出现的位置public int search(int toFind) {for (int i = 0; i < this.usedSize; i++) {if(this.elem[i] == toFind) {return i;}}return -1;}//获取顺序表的长度public int size() {return this.usedSize;}//删除第一次出现的Keypublic void remove(int toRemove) {int index = search(toRemove);if(index == -1) {System.out.println("没有要删除的数据");return;}for (int i = index; i < this.usedSize - 1; i++) {this.elem[i] = this.elem[i+1];}this.usedSize--;}//更新pos处的值public void setPos(int pos, int data) {checkPos(pos);this.elem[pos] = data;}//清除顺序表public void clear() {this.usedSize = 0;}
}

总结

经过对顺序表的实现,我们知道了各个接口的原理,同时发现顺序表的头插、头删、随机插入,随机删除相对于尾插和尾删都十分麻烦,原因在于我们必须要挪动数据,而且需要十分小心的控制插入或删除的边界,否则会导致插入的数据把原始数据覆盖等一系列问题。但对于链表,我们不需要这么麻烦,我们只需要改变指针的指向即可,对于链表的实现,我们下期再说。

数据结构——顺序表的实现相关推荐

  1. C语言链表的转置算法,c语言编程集 数据结构 顺序表 点链表 数制转换 矩阵转置.doc...

    c语言编程集 数据结构 顺序表 点链表 数制转换 矩阵转置 #include "stdio.h" #include "malloc.h" /*typedef s ...

  2. 数据结构-顺序表(动态分配存储空间)

    数据结构-顺序表(动态分配存储空间) (1)顺序表的结构定义: 结构型定义:(动态分配存储空间) /*** 动态分配存储空间*/ #define InitSize 100 //动态分配存储空间时,不限 ...

  3. C语言/C++常见习题问答集锦[八十三]之数据结构顺序表(operand types are error: no match for “operator==“)

    C语言/C++常见习题问答集锦[八十三]之数据结构顺序表{operand types are error: no match for "operator=="} 程序之美 前言 主 ...

  4. 数据结构--顺序表的使用

    数据结构--顺序表的使 #include<iostream> #include<cstdio> #include<cstring> using namespace ...

  5. Educoder头歌数据结构顺序表及其应用

    头歌实践平台答案educoder 数据结构-顺序表及其应用 第1关:顺序表的实现之查找功能 /***************************************************** ...

  6. 数据结构——顺序表的合并

    数据结构--顺序表的合并 具体要求:写一个函数,其函数的功能是将非递增顺序表LA和LB合并到非递增顺序表LC中 数据结构-顺序表的操作之合并顺序表 一.顺序表的结构 首先要定义的是顺序表的结构体,只有 ...

  7. python顺序表数组_数据结构 | 顺序表

    什么是数据结构? 数据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成. 简单来说,数据结构就是设计数据以何种方式组织并存储在计算机中. 比如:列表.集合与字典等都 ...

  8. 8.基本数据结构-顺序表和链表

    一.内存 - 计算机的作用:对数据进行存储和运算.首先我们需要知道我们目前使用的计算机都是二进制的计算机,就以为着计算机只可以存储和运算二进制的数据.例如下载好的一部电影,该电影可以存储到计算机中,计 ...

  9. 数据结构顺序表基本流程

    生活中很多事物是有顺序关系的,如班级座位从前到后是按排的顺序,从左到右是按列的顺序,可以很方便的定位到某一个位置,但如果座位是散乱的,就很难定位. 在程序中,经常需要将一组(通常是同为某个类型的)数据 ...

  10. C#数据结构-顺序表

    顺序表,顾名思义存储在计算机指定内存区域的一块连续的存储结构,跟我们一起排队做广播体操的那种方式 存储物理结构:物理内存空间上是连续的 存储逻辑关系:存储值之间的关系为一对一 使用场景:一般访问数据量 ...

最新文章

  1. ​多视图立体视觉: CVPR 2019 与 AAAI 2020 上的ACMH、ACMM及ACMP算法介绍
  2. ADO.NET Data Services Framework 基础概述
  3. Matlab非线性方程求解
  4. BUAA-OO-第三单元总结
  5. PyCharm设置字体大小(亲测)
  6. js Blob对象介绍
  7. 计算机管理中看不到本地用户,win7系统计算机管理中没有本地用户和组的解决方法...
  8. Basic4android v3.50 发布
  9. Android xmlns 的作用及其自定义
  10. Mixtile Garage产品简介
  11. 写烂代码的人离职之后...
  12. 低压电力线宽带载波通信互联互通技术规-总则
  13. PipeCAD 简介
  14. 关于CSS Reset 那些事(一)之 历史演变与Normalize.css
  15. 在VM虚拟机下安装win7系统
  16. 【工业大数据】工业大数据应用场景分析;工业大数据,从何做起
  17. 【项目排期】测试排期问题思考
  18. 移动周报:85后程序员,iOS开源项目,细数7天大事件!
  19. 学习笔记(11):OmniPlan项目管理就该这样学-拆分任务
  20. ChatGPT 以及相关开源项目体验

热门文章

  1. pom文件配置阿里云仓库 转
  2. 再爆 Bug!Windows 11 任务栏、菜单栏无故消失,怎么解?
  3. 不为人知的黑科技||双十一薅羊毛正确姿势
  4. 淘宝标题核心关键词怎么做?大神导航,一个神奇的网站,从此开启大神之路!
  5. 天平游码读数例题_天平游码读数
  6. 【React】Mobx
  7. 十进制转换为任意进制的算法代码
  8. java实现整数翻转
  9. 【php图片上传在网页显示】
  10. originPro2021(3)添加图例导出图片图例不完全