数据结构初阶 顺序表的讲解

简介: 数据结构初阶 顺序表的讲解

一. 线性表


1.1 定义


线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串…

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


看这个定义 我们再联想前面的知识


是不是发现数组的使用和这个定义十分相似


没错 其实顺序表本质上就是数组


但是它再数组上增加了一点内容


1.2 特点


它分为静态的和动态的


这个特点是不是又发现和我们上面做的项目通讯录十分相似


它是连续存储的 不能跳过元素


二. 顺序表


2.1 定义


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


2.2 代码


struct SeqList
{
  int a[100]; //数组
  int size; //数组中存储了多少个数字 
};
• 1


我们说类似这个结构的 就是一个顺序表


但是呢 为了我们以后改变数字方便 我们可以把这里的100 定义成一个宏 这样我们以后如果想修改顺序


表的大小 只要改变宏就可以了


代码表示如下


// 静态顺序表
#define N 100
struct SeqList
{
  int a[N]; //数组
  int size; //数组中存储了多少个数字 
};


上面就是一个标准的静态数据表 假如说 我们想使用顺序表来管理一个字符串


#define N 100
struct SeqList
{
  char a[N]; //数组
  int size; //数组中存储了多少个数字 
};

一个宏变量


#define N 100
typedef char SLDateType
struct SeqList
{
  int SLDateType[N]; //数组
  int size; //数组中存储了多少个数字 
};


我们说 就可以使用这样的格式 方便以后一次性改变所有的变量类型


但是呢 这样子我们看整个结构体还是有点麻烦 我们再将这个结构体简化一下


typedef struct SeqList
{
  int SLDateType[N]; //数组
  int size; //数组中存储了多少个数字 
}SL;


这样子就能得到一个相对完美的静态顺序表啦


2.3 功能需求


在创建好这个静态表之后 我们要开始大概创建它的一些功能啦


比如说以下的一些功能


vovoid SeqListInit(SL* ps);
void SeqListPushBack(SL* ps, SLDateType x);
void SeqListPopBack(SL* ps);
void SeqListPushFront(SL* ps, SLDateType x);
void SeqListPopFront(SL* ps);


初始化 尾插 头插等等


2.4 静态顺序表的特点以及缺点


特点: 如果满了就不让插入


缺点: 不知道给多少合适


2.5 动态的顺序表


typedef struct SeqList
{
  SLDateType* a; //数组
  int size; //数组中存储了多少个数字 
  int capacity;
}SL;


是不是跟我们的通讯录特别相似


其实原理本质上都是一样的 这里只是命名更加规范了


2.6 动态顺序表接口的实现


初始化


void SeqListInit(SL* ps)
{
  ps->a = NULL;
  ps->size = ps->capacity = 0;
}


尾插

724c4520df344144b97e962851c62c2e.png


我们先写空间足够的情况


void SeqListPushBack(SL* ps, SLDateType x)
{
  ps->a[ps->size] = x;
  ps->size++;
}


代码表示如上


那么我们接下来我们写上面的两种情况


这里我们要注意的是 一开始我们将指针置空 占用的空间为0


所以说我们一开始至少要开始4个数据的空间 这里可以使用一个三目操作符解决


int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
• 1


养成良好的习惯 代码加注释


void SeqListPushBack(SL* ps, SLDateType x)
{
  // 如果没有空间或者空间不足 我们就扩容 
  // 扩容失败就报错
  if ((ps->size)==(ps->capacity))
  {
    int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
    SLDateType* tmp =(SLDateType*)realloc(ps->a, newcapacity * sizeof(SLDateType));
    if (tmp==NULL)
    {
      perror("pushback realloc");
    }
  }
  ps->a[ps->size] = x;
  ps->size++;
}


这里我们使用一个打印函数看看整个数据的内容


void SeqListPrint(SL* ps)
{
  int i = 0;
  for ( i = 0; i < ps->size; i++)
  {
    printf("%d ", ps->a[i]);
  }
  printf("\n");
}

打印出结果如下


d8fe0450c98146648e177bb060c71f41.png


在使用完成之后我们还需要一个借口函数来释放我们的动态开辟的内存 从而避免内存泄漏的问题


void SeqListDestory(SL* ps)
{
  free(ps->a);
  ps->a == NULL;
  ps->capacity = ps->size = 0;
}


接下来我们看尾删函数


void SeqListPopBack(SL* ps)
{
  ps->size--;
}



尾删的话其实我们只要将size-- 就可以


但是这里我们要注意一点 当size为0的时候 这里就不可以再删除了 所以我们还需要完善以下上面的代码


void SeqListPopBack(SL* ps)
{
  if (ps->size==0)
  {
    perror("SeqListPopBack");
  }
  ps->size--;
}


接下来我们看前插


void SeqListPushFront(SL* ps, SLDateType x)
{
  // 考虑扩容问题
  if ((ps->size) == (ps->capacity))
  {
    int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
    ps->capacity = newcapacity;
    SLDateType* tmp = (SLDateType*)realloc(ps->a, newcapacity * sizeof(SLDateType));
    if (tmp == NULL)
    {
      perror("pushback realloc");
    }
    ps->a = tmp;
  }
  // 头插
  int end = ps->size - 1;
  while (end>=0)
  {
    ps->a[end + 1] = ps->a[end];
  }
  ps->a[0] = x;
  ps->size++;
}


接下来我们来看头删

fe8f3c551d8344e7a21aa7984f698770.png


这就要求我们定义一个bejin 然后从前往后依次挪数据


代码表示如下


void SeqListPopFront(SL* ps)
{
  int bejin = 0;
  while (bejin<ps->size-1)
  {
    ps->a[bejin] = ps->a[bejin + 1];
    bejin++;
  }
  ps->size--;
}


300f738d6a6e474eaff236847fab9f63.png


这里我们基本实现了顺序表的所有接口函数啦


三. 代码


头文件

#pragma once
#define N 100
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLDateType;
typedef struct SeqList
{
  SLDateType* a; //数组
  int size; //数组中存储了多少个数字 
  int capacity;
}SL;
void SeqListInit(SL* ps);
void SeqListDestory(SL* ps);
void SeqListPushBack(SL* ps, SLDateType x);
void SeqListPopBack(SL* ps);
void SeqListPushFront(SL* ps, SLDateType x);
void SeqListPopFront(SL* ps);
void SeqListPrint(SL* ps);
// . 
//...


主文件

#define _CRT_SECURE_NO_WARNINGS 1
#include "seqlist.h"
void SeqListInit(SL* ps)
{
  ps->a = NULL;
  ps->size = ps->capacity = 0;
}
void SeqListPrint(SL* ps)
{
  int i = 0;
  for ( i = 0; i < ps->size; i++)
  {
    printf("%d ", ps->a[i]);
  }
  printf("\n");
}
void SeqListPushBack(SL* ps, SLDateType x)
{
  // 如果没有空间或者空间不足 我们就扩容 
  // 扩容失败就报错
  if ((ps->size)==(ps->capacity))
  {
    int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
    ps->capacity = newcapacity;
    SLDateType* tmp =(SLDateType*)realloc(ps->a, newcapacity * sizeof(SLDateType));
    if (tmp==NULL)
    {
      perror("pushback realloc");
    }
    ps->a = tmp;
  }
  ps->a[ps->size] = x;
  ps->size++;
}
void SeqListDestory(SL* ps)
{
  free(ps->a);
  ps->a = NULL;
  ps->capacity = ps->size = 0;
}
void SeqListPopBack(SL* ps)
{
  if (ps->size==0)
  {
    perror("SeqListPopBack");
  }
  ps->size--;
}
void SeqListPushFront(SL* ps, SLDateType x)
{
  // 考虑扩容问题
  if ((ps->size) == (ps->capacity))
  {
    int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
    ps->capacity = newcapacity;
    SLDateType* tmp = (SLDateType*)realloc(ps->a, newcapacity * sizeof(SLDateType));
    if (tmp == NULL)
    {
      perror("pushback realloc");
    }
    ps->a = tmp;
  }
  // 头插
  int end = ps->size - 1;
  while (end >= 0)
  {
    ps->a[end + 1] = ps->a[end];
    end--;
  }
  ps->a[0] = x;
  ps->size++;
}
void SeqListPopFront(SL* ps)
{
  int bejin = 0;
  while (bejin<ps->size-1)
  {
    ps->a[bejin] = ps->a[bejin + 1];
    bejin++;
  }
  ps->size--;
}


测试文件

#define _CRT_SECURE_NO_WARNINGS 1
#include "seqlist.h"
int main()
{
  SL a1;
  SeqListInit(&a1);
  SeqListPushBack(&a1, 1);
  SeqListPushBack(&a1, 2);
  SeqListPushBack(&a1, 3);
  SeqListPushBack(&a1, 4);
  SeqListPushBack(&a1, 5);
  SeqListPrint(&a1);
  SeqListPopBack(&a1);
  SeqListPrint(&a1);
  SeqListPopFront(&a1);
  SeqListPrint(&a1);
  SeqListDestory(&a1);
  return 0;
}


以上就是本篇博客的全部内容啦 由于博主才疏学浅 所以难免会出现纰漏 希望大佬们看到错误之后能够


不吝赐教 在评论区或者私信指正 博主一定及时修正


那么大家下期再见咯

相关文章
|
3月前
|
存储 编译器 C语言
数据结构-顺序表详解(看这篇就足够了,哈哈哈)
数据结构-顺序表详解(看这篇就足够了,哈哈哈)
74 2
|
5天前
|
机器学习/深度学习 存储 C++
【C++数据结构——线性表】顺序表的基本运算(头歌实践教学平台习题)【合集】
本文档介绍了线性表的基本运算任务,涵盖顺序表和链表的初始化、销毁、判定是否为空、求长度、输出、查找元素、插入和删除元素等内容。通过C++代码示例详细展示了每一步骤的具体实现方法,并提供了测试说明和通关代码。 主要内容包括: - **任务描述**:实现顺序表的基本运算。 - **相关知识**:介绍线性表的基本概念及操作,如初始化、销毁、判定是否为空表等。 - **具体操作**:详述顺序表和链表的初始化、求长度、输出、查找、插入和删除元素的方法,并附有代码示例。 - **测试说明**:提供测试输入和预期输出,确保代码正确性。 - **通关代码**:给出完整的C++代码实现,帮助完成任务。 文档
22 5
|
19天前
|
数据库
数据结构中二叉树,哈希表,顺序表,链表的比较补充
二叉搜索树,哈希表,顺序表,链表的特点的比较
数据结构中二叉树,哈希表,顺序表,链表的比较补充
|
2月前
|
存储 算法 安全
2024重生之回溯数据结构与算法系列学习之顺序表【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】
顺序表的定义和基本操作之插入;删除;按值查找;按位查找等具体详解步骤以及举例说明
|
2月前
|
存储 C语言
【数据结构】顺序表(c语言实现)(附源码)
本文介绍了线性表和顺序表的基本概念及其实现。线性表是一种有限序列,常见的线性表有顺序表、链表、栈、队列等。顺序表是一种基于连续内存地址存储数据的数据结构,其底层逻辑是数组。文章详细讲解了静态顺序表和动态顺序表的区别,并重点介绍了动态顺序表的实现,包括初始化、销毁、打印、增删查改等操作。最后,文章总结了顺序表的时间复杂度和局限性,并预告了后续关于链表的内容。
95 3
|
2月前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之顺序表习题精讲【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】
顺序表的定义和基本操作之插入;删除;按值查找;按位查找习题精讲等具体详解步骤以及举例说明
|
3月前
|
存储 Java
数据结构第二篇【关于java线性表(顺序表)的基本操作】
数据结构第二篇【关于java线性表(顺序表)的基本操作】
52 6
|
3月前
|
存储
数据结构(顺序表)
数据结构(顺序表)
32 0
|
3月前
|
存储 算法
【数据结构】新篇章 -- 顺序表
【数据结构】新篇章 -- 顺序表
26 0
|
3月前
|
存储 测试技术
探索数据结构:顺序表的实现与应用
探索数据结构:顺序表的实现与应用