顺序表的实现(详解版)

简介: 顺序表的实现(详解版)

7182c130ddc4487a95b9154da5a6a806.jpg

概念以及分类

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

顺序表一般可以分为

  1. 静态顺序表:使用定长数组存储。
  2. 动态顺序表:使用动态开辟的数组存储。

静态顺序表

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

动态顺序表(重点掌握)

简单介绍(主体+接口函数)

#pragma once  // 防止被重复包含
#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 SeqListPrint(SL* ps); //顺序表的打印
void SeqListnewcapacity(SL* ps); //检查是否需要增容
void SeqListDestory(SL* ps); // 清除数据
void SeqListPopBack(SL* ps); // 尾插
void SeqListPushBack(SL* ps, SLDateType x); // 尾删
void SeqlistPushFront(SL * ps, SLDateType x); // 头插
void SeqListPopFront(SL* ps, SLDateType x); //头删
void SeqLisFind(SL* ps, SLDateType x); //查找元素
void SeqListInsert(SL* ps, int pos, SLDateType x); //任意位置插入
void SeqListErase(SL* ps, int pos, SLDateType x); //任意位置删除

首选需要说明的,这接口函数的命名风格是跟着STL走的,这样命名有助于C++的学习。

顺序表的主体由三部分组成

1.插入的数据

2.插入数据的容量

3.该顺序表的最大容量

注意:

1.这里使用了typedef int SLDateType;,是为了后面方便对插入的数据类型进行修改

2.typedef struct SeqList ,是为了后面 用SL代替, 表示比较方便

初始化函数(SeqListInit(SL * ps))

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

初始化步骤很简单,就让数据容量都为0, 而传入的值都为NULL。

打印函数(void SeqListPrint(SL* ps))

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

这也很简单, 就用有个for循环, 挨着打印顺序表中的每个。

是否增容函数(SeqListnewcapacity(SL* ps))

void SeqListnewcapacity(SL* ps)
{
  if (ps->size == ps->capacity)       //扩容或者是开辟空间
  {
    int newcapacity = ps->size == 0 ? 4 : ps->capacity * 2;
    SLDateType* tmp = (SLDateType*)realloc(ps->a, newcapacity * sizeof(SLDateType)); //realloc(a, b) 若a = NULL,相当于开辟空间
    //  a != NULL 扩容
/*if (tmp == NULL)
{
  printf("开辟空间失败");
  exit(-1);
}*/
    assert(tmp != NULL);
    ps->a = tmp;
    ps->capacity = newcapacity;
  }

判断是否需要增容的条件是:

ps->size == ps->capacity

实际用的容量==顺序表最大容量

代表着顺序表已经没有多余读的空间,来存储下一个数据了

这里分两种情况:

1.如果ps->size = ps->capacity == 0;,那么让它等于4

2.如果ps->size = ps->capacity != 0;, 那么就 让它的最大容量加倍(当然这里你可以自己随便设置)

这两种情况的实现,这里使用了三目运算符

情况2:

这里使用了realloc函数,来进行增容。

realloc(a, b) 若a = NULL,相当于开辟空间

a != NULL 扩容

注意:

1.newcapacity * sizeof(SLDateType),需要扩容的空间大小 = 数据的个数 * 它的数据类型

2.开辟空间,自然要考虑到开辟空间失败的情况

清楚数据函数(SeqListDestory(SL* ps))

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

这里主要就使用free函数,对内存进行释放

ps->a = NULL;

ps->capacity = ps->size == 0;

尾插函数(SeqListPopBack(SL* ps))

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

尾插:就是在顺序表最后一个元素的后面插入一个元素

第一步:检查是否要增容

第二步:在顺序表后面插入元素 ,ps->size 表示此时顺序表中所存储的个数, ps->size - 1是顺序表中最后一个元素(数组下标), ps->size 自然就是最后一个元素的后面

第三步:插入了一个元素之后,自然就要让顺序表中存储的元素个数+1, ps->size + 1;

尾删函数(SeqListPushBack(SL* ps, SLDateType x); )

void  SeqListPopBack(SL* ps)
{
  /*if (ps->a > 0)
  {
    ps->size--;
  }*/
  assert(ps->a > 0);
  ps->size--;
}

尾删:从数组的最后一个元素开始删除

删除的前提自然是 ps->szie > 0;

这里有2种解决方法

1:温柔的方式 ;用if语句来判断

2:粗暴的方式:用assert(),直接断言,如果不正确,直接就终止程序

注意要使用头文件(#inlucde<assert.h>)

删除方式:

通过让存贮的数据总数减少(ps->size–),从而达到从数组的最后一个元素开始删除的效果.

头插 (SeqlistPushFront(SL * ps, SLDateType x))

void SeqlistPushFront(SL* ps, SLDateType x)
{
  SeqListnewcapacity(ps);
  int end = ps->size - 1;
  while (end >= 0)
  {
    ps->a[end + 1] = ps->a[end];
    end--;
  }
  ps->a[0] = x;
  ps->size++;
}

头插:在数组第一个元素的前面插入一个数据

主要思想

前面插入一个数据,这里就涉及到一个挪移数据的过程,

也就是新插入的数据,就是顺序表数组中的第一个元素。, 那么就要挪出一个位置, 原来数组中每个元素向后面挪一位, 自然便能把数组的第一个位置空出来。(通过赋值操作,把元素的值赋值给下一位)

第一步:检查是否需要增容

第二步:插入数据并且开始挪移数据

end为数组元素的最后一位

这里让ps->a[end + 1] = ps->a[end];, 通过赋值操作,把元素的值赋值给下一位,然后end–, 继续挪动数据,这里自然是一个循环,while(end >= 0);

第三步::插入了一个元素之后,自然就要让顺序表中存储的元素个数+1, ps->size + 1;

头删函数(SeqListPopFront(SL* ps, SLDateType x); )

void SeqListPopFront(SL* ps, SLDateType x)
{
  assert(ps->size > 0);
  int begin = 1;
  while (begin < ps->size)
  {
    ps->a[begin - 1] = ps->a[begin];
    begin++;
  }
  ps->size--;
}

头删:从数组的第一个元素开始删除

思想:(采用赋值删除的思想

第二个值赋给第一个值, 第三个个值赋给第二个值,这样第一个元素自然就被消掉了,结果自然是每个元素向前移一位,也是通过赋值的操作

(挪移数据跟头插相似, 只是挪移的方向不一样)

第一步:删除元素,肯定要考虑越界问题 ps->size > 0

assert(ps->size > 0);

第二步:

beign 代表数组第一个元素的下标

通过赋值操作挪移数据,第二个值赋给第一个值, 第三个个值赋给第二个值,ps->a[begin - 1] = ps->a[begin];

begin++,挪动下一组数据

循环条件:while (begin < ps->size)

第三步:

删除了一个元素之后,自然就要让顺序表中存储的元素个数-1, ps->size - 1;

查找任意位置的函数( SeqLisFind(SL* ps, SLDateType x); )

void SeqLisFind(SL* ps, SLDateType x)
{
  for(int i = 0; i < ps->size; i++)
  {
    if (ps->a[i] == x)
    {
      return i;
    }
    return -1;
  }
}

查找元素,其实很简单

自然,

就是通过for循环和if语句, 与顺序表中的每个数据进行比较

找到的话, 就返回就这个数组的元素位置的下标

插入任意位置的函数(SeqListInsert(SL* ps, int pos, SLDateType x); )

oid SeqListInsert(SL* ps, int pos, SLDateType x)
{
  assert(pos >= 0 && pos <= ps->size);
  int end = ps->size - 1;
  while (pos <= ps->size)
  {
    ps->a[end + 1] = ps->a[end];
    end--;
  }
  ps->a[pos] = x;
  ps->size++;
}

第一步:自然要进行一个判断, 插入的位置肯定在这个数组中,不能够造成越界的非法操作,这里我还是用的assert函数来进行处理,当然你如果用if语句的话也是可以的。

第二步:里面插入了一个数据,自然要向后面挪移一个数据来腾出空间
end代表数组的最后一个元素

在pos位置之后的元素,都向后挪移一位

循环条件自然是:pos <= ps->size

while (pos <= ps->size)

{

ps->a[end + 1] = ps->a[end];

end–;

}

第三步:腾出的位置,赋值给插入的数据ps->a[pos] = x;

第四步:插入了一个元素之后,自然就要让顺序表中存储的元素个数+1, ps->size + 1;

运用:

如果pos = 0, 那么其实这就是头插
如果pos = ps->size, 那么这也就是尾插

任意位置删除的函数(SeqListErase(SL* ps, int pos, SLDateType x); )

void SeqListErase(SL* ps, int pos, SLDateType x)
{
  assert(pos >= 0 && pos < ps->size);
  int begin = pos + 1;
  while (begin <= ps->size)
  {
    ps->a[begin - 1] = ps->a[begin + 1];
    begin++;
  }
  ps->size--;
}

第一步:

自然要进行一个判断, 删除的位置肯定在这个数组中,不能够造成越界的非法操作,这里我还是用的assert函数来进行处理,当然你如果用if语句的话也是可以的。

第二步:挪移数据,pos之后的元素向前挪移一个数据,通过赋值删除的方法。方法跟思路也是跟之前一样的。

while (begin <= ps->size)

{

ps->a[begin - 1] = ps->a[begin + 1];

begin++;

}

第三步:删除了一个元素之后,自然就要让顺序表中存储的元素个数-1, ps->size - 1;

运用:

1.同样的如果pos = 0,那么这就是头删

2,如果pos = ps->size - 1,那么这就是尾删

小总结

1.删除是向前挪移数据

2.插入式向后挪移数据

3.挪移数据的目的,是为了让数据在内存存储中是连续的

希望这能够对你们有所帮助,你们的关注与支持就是对我最大的鼓励


相关文章
|
6月前
|
存储 测试技术 C语言
顺序表详解(SeqList)
顺序表详解(SeqList)
177 0
|
存储
【顺序表】
【顺序表】
51 0
|
5月前
|
算法
顺序表的应用
顺序表的应用
37 5
|
5月前
|
存储 算法
顺序表专题
顺序表专题
40 4
|
5月前
|
存储
25.顺序表专题
25.顺序表专题
|
6月前
|
存储
顺序表讲解
顺序表讲解
49 0
|
6月前
顺序表的实现
顺序表的实现
|
测试技术
顺序表(2)
顺序表(2)
549 0
|
存储 C语言
顺序表(1)
顺序表(1)
77 0
|
存储 NoSQL
03 顺序表
03 顺序表
32 0