手撕顺序表

简介: 手撕顺序表

> 作者简介:დ旧言~,目前大一,现在学习Java,c,c++,Python等

> 座右铭:松树千年终是朽,槿花一日自为荣。

> 望小伙伴们点赞👍收藏✨加关注哟💕💕      

🌟前言      

       梦回数组,当我们开辟了一个数组,数组的大小就已经确定了,不能括容,也不能减容,为了解决这个问题,在数据结构有一个这样的知识--《顺序表》。顺序表连续开辟一个空间,能括容,也能减容,今天我们手撕顺序表。

🌙主体

咱们从三个方面实现顺序表动态管理,头插头删尾插尾删,增删查改。

在程序中为了实现顺序表,需要创建头文件SeqList.h ,创建源文件test.c,SeqList.c。

🌠动态管理

💤初始化动态顺序表

  1. 首先定义一个结构体(在源文件中),结构体里面有可变数组(a),数组初始长度(size),初始空间(capacity)。
  2. 初始化动态顺序表(SeqList.h中),需要开辟空间,再判断空间是否为空,再初始化数组长度,空间。
//动态顺序表
typedef int SLDataType;
typedef struct SeqList
{
   //定义一个可变数组
  SLDataType* a;
   //定义数组初始长度
   int size;
   //定义空间大小
   int capacity;
}SL;
//初始化动态顺序表
void SLInit(SL* ps)
{
  //开辟空间
  ps->a = (SLDataType*)malloc(sizeof(SLDataType*) * 4);
  //判断空间是否为空
  if (ps->a == NULL)
  {
    perror("malloc failed");
    exit(-1);
  }
  //初始化
  ps->size = 0;
  ps->capacity = 4;
}

1.防止一直创建结构体,为了一劳永逸,我们把动态顺序表放在源文件中。

2.这里我们用typedef int SLDataType,给数据类型重定义名字,这样就可以防止修改数据类型。

💤扩容顺序表空间

数组初始长度(size),初始空间(capacity)相同时,这里们就需要扩容,这里我们扩容两倍。(在头文件中SeqList.c中)

//扩容空间
void SLCheckCapacity(SL* ps)
{
  //如果size和capacity相同
  if (ps->size == ps->capacity)
  {
    //扩大两倍
    SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(SLDataType));
    //判断tmp是否为空
    if (tmp == NULL)
    {
      perror("realloc failed");
      exit(-1);
    }
    //赋值
    ps->a = tmp;
    ps->capacity = ps->capacity * 2;
  }
}

💤释放顺序表内存

可变数组(a)置为(NULL),数组长度(size)置为(0),初始空间(capacity)置为(0)。

//释放内存
void SLDestroy(SL* ps)
{
  //断言
  assert(ps);
  free(ps->a);
  ps->a = NULL;
  ps->size = 0;
  ps->capacity = 0;
}

🌠头插头删尾插尾删

💤添加元素

首先需要断言防止顺序表为空。这里需要注意空间是否满了。这里的实现和在pos位置插入x有类似,等我们实现这个函数,就可以直接调用这个函数,更加简便。(在头文件中SeqList.c中)

//添加元素
void SLPushBack(SL* ps, SLDataType x)
{
  //断言
  assert(ps);
  //判断空间是否满了,需要调用函数
  SLCheckCapacity(ps);
  //添加元素
  ps->a[ps->size] = x;
  ps->size++;
  //在pos位置插入x
  //SLInsert(ps, ps->size, x);
}

💤打印元素

打印元素太简单啦,直接用for循环就行。(在头文件中SeqList.c中)

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

💤尾删

直接在末尾删除就行,之后这里只要size减减就好了,后面的元素会覆盖。这里的实现和在pos位置插入x有类似,等我们实现这个函数,就可以直接调用这个函数,更加简便。(在头文件中SeqList.c中)

//尾删
void SLPopBack(SL* ps)
{
  //断言
  assert(ps);
  // 温柔的检查
  //if (ps->size == 0)
    //return;
  // 暴力的检查
  assert(ps->size > 0);
  //ps->a[ps->size - 1] = 0;
  //这里只要size减减就好了,后面的元素会覆盖
  ps->size--;
  //删除pos位置的值
  //SLErase(ps, ps->size - 1);
}

💤头插(重点)

这里需要注意要让ps->size加加这里的实现和在pos位置插入x有类似,等我们实现这个函数,就可以直接调用这个函数,更加简便。(在头文件中SeqList.c中)

//头插
void SLPushFront(SL* ps, SLDataType x)
{
  //断言
  assert(ps);
  //定义最后一个元素
  int end = ps->size - 1;
  //循环
  while (end >= 0)
  {
    ps->a[end + 1] = ps->a[end];
    end--;
  }
  //x赋给最前的数字
  ps->a[0] = x;
  //指向下一个数字
  ps->size++;
  //在pos位置插入x
  //SLInsert(ps, 0, x);
}

💤头删(重点)

这里需要注意要让ps->size减减这里的实现和删除pos位置的值相似,等我们实现这个函数,就可以直接调用这个函数,更加简便。(在头文件中SeqList.c中)

//头删
void SLPopFront(SL* ps)
{
  //断言
  assert(ps);
  //断言(指向不能为零)
  assert(ps);
  //指向头前面的那个数字
  int begin = 1;
  //循环
  while (begin < ps->size)
  {
    ps->a[begin - 1] = ps->a[begin];
    begin++;
  }
  ps->size--;
  //删除pos位置的值
  //SLErase(ps, 0);
}

 🌠增删查改

💤在pos位置插入x

首先这里需要判断pos是否在数组空间内,其次判断空间是否充足,然后循环,最后ps->size++

这里的插入本质和头插相似。(元素向后移动一格)

//在pos位置插入x
void SLInsert(SL* ps, int pos, SLDataType x)
{
  //断言,这里pos
  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++;
}

💤删除pos位置的值

首先这里需要判断pos是否在数组空间内,其次判断空间是否充足,然后循环,最后ps->size--

这里的删除本质和头删相似。(元素向前移动一格)

//删除pos位置的值
void SLErase(SL* ps, int pos)
{
  //断言
  assert(ps);
  //断言pos
  assert(pos >= 0 && pos < ps->size);
  int begin = pos + 1;
  while (begin < ps->size)
  {
    ps->a[begin - 1] = ps->a[begin];
    ++begin;
  }
  ps->size--;
}

💤修改pos位置的信息

这个实现太简单啦。

//修改pos位置的信息
void SLModify(SL* ps, int pos, SLDataType x)
{
  //断言
  assert(ps);
  //判断pos
  assert(pos >= 0 && pos < ps->size);
  //直接换
  ps->a[pos] = x;
}

🌠主函数

int main()
{
    //定义结构体
  SL sl;
  //初始动态列表
  SLInit(&sl);
  //释放内存
  SLDestroy(&sl);
    return 0;
}

🌙代码总结

🌠主函数

//主函数(包含头文件)
#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);
  //打印元素
  SLPrint(&sl);
  //添加元素
  SLPushBack(&sl, 1);
  SLPushBack(&sl, 2);
  //打印元素
  SLPrint(&sl);
  //释放内存
  SLDestroy(&sl);
}
//头删
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);
  //头删
  SLPopFront(&sl);
  SLPopFront(&sl);
  SLPopFront(&sl);
  //打印元素
  SLPrint(&sl);
  //释放内存
  SLDestroy(&sl);
}
//在pos位置插入x
void TestSeqList3()
{
  //定义结构体
  SL sl;
  //初始动态列表
  SLInit(&sl);
  //添加元素
  SLPushBack(&sl, 1);
  SLPushBack(&sl, 2);
  SLPushBack(&sl, 3);
  SLPushBack(&sl, 4);
  SLPushBack(&sl, 5);
  //打印元素
  SLPrint(&sl);
  //在pos位置插入x
  int input = 0;
  printf("请输入插入的位置:");
  scanf("%d", &input);
  int number = 0;
  printf("请输入插入的数字:");
  scanf("%d", &number);
  SLInsert(&sl, input, number);
  //打印元素
  SLPrint(&sl);
  //释放内存
  SLDestroy(&sl);
}
//删除pos位置的值
void TestSeqList4()
{
  //定义结构体
  SL sl;
  //初始动态列表
  SLInit(&sl);
  //添加元素
  SLPushBack(&sl, 1);
  SLPushBack(&sl, 2);
  SLPushBack(&sl, 3);
  SLPushBack(&sl, 4);
  SLPushBack(&sl, 5);
  //打印元素
  SLPrint(&sl);
  //删除pos位置的值
  int input = 0;
  printf("请输入删除的位置:");
  scanf("%d", &input);
  SLErase(&sl, input);
  //打印元素
  SLPrint(&sl);
  //释放内存
  SLDestroy(&sl);
}
//删除pos位置的值
void TestSeqList5()
{
  //定义结构体
  SL sl;
  //初始动态列表
  SLInit(&sl);
  //添加元素
  SLPushBack(&sl, 1);
  SLPushBack(&sl, 2);
  SLPushBack(&sl, 3);
  SLPushBack(&sl, 4);
  SLPushBack(&sl, 5);
  //打印元素
  SLPrint(&sl);
  //修改pos位置的信息
  int input = 0;
  printf("请输入需要修改的位置:");
  scanf("%d", &input);
  int number = 0;
  printf("请输入需要修改的数字:");
  scanf("%d", &number);
  SLModify(&sl, input, number);
  //打印元素
  SLPrint(&sl);
  //释放内存
  SLDestroy(&sl);
}
int main()
{
  //TestSeqList1();
  //TestSeqList2();
  //TestSeqList3();
  //TestSeqList4();
  TestSeqList5();
  return 0;
}

🌠SeqList.h头文件

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//动态顺序表
typedef int SLDataType;
typedef struct SeqList
{
   //定义一个可变数组
  SLDataType* a;
   //定义数组初始长度
   int size;
   //定义空间大小
   int capacity;
}SL;
//动态管理
//初始化动态顺序表
void SLInit(SL* ps);
//释放内存
void SLDestroy(SL* ps);
//打印数组
void SLPrint(SL* ps);
//扩容空间
void SLCheckCapacity(SL* ps);
// 头插头删 尾插尾删
void SLPushBack(SL* ps, SLDataType x);//添加元素
void SLPopBack(SL* ps);//尾删
void SLPushFront(SL* ps, SLDataType x);//头插元素
void SLPopFront(SL* ps);//头删
//返回下标,没有找打返回-1
int SLFind(SL* ps, SLDataType x);
//在pos位置插入x
void SLInsert(SL* ps, int pos, SLDataType x);
//删除pos位置的值
void SLErase(SL* ps, int pos);
//修改pos位置的信息
void SLModify(SL* ps, int pos, SLDataType x);

🌠SeqList.c源文件

#include"SeqList.h"
//初始化动态顺序表
void SLInit(SL* ps)
{
  //开辟空间
  ps->a = (SLDataType*)malloc(sizeof(SLDataType*) * 4);
  //判断空间是否为空
  if (ps->a == NULL)
  {
    perror("malloc failed");
    exit(-1);
  }
  //初始化
  ps->size = 0;
  ps->capacity = 4;
}
//释放内存
void SLDestroy(SL* ps)
{
  //断言
  assert(ps);
  free(ps->a);
  ps->a = NULL;
  ps->size = 0;
  ps->capacity = 0;
}
//打印数组
void SLPrint(SL* ps) 
{
  for (int i = 0; i < ps->size; i++)
  {
    printf("%d ", ps->a[i]);
  }
  printf("\n");
}
//扩容空间
void SLCheckCapacity(SL* ps)
{
  //如果size和capacity相同
  if (ps->size == ps->capacity)
  {
    //扩大两倍
    SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(SLDataType));
    //判断tmp是否为空
    if (tmp == NULL)
    {
      perror("realloc failed");
      exit(-1);
    }
    //赋值
    ps->a = tmp;
    ps->capacity = ps->capacity * 2;
  }
}
//添加元素
void SLPushBack(SL* ps, SLDataType x)
{
  //断言
  assert(ps);
  /*//判断空间是否满了,需要调用函数
  SLCheckCapacity(ps);
  //添加元素
  ps->a[ps->size] = x;
  ps->size++;*/
  //在pos位置插入x
  SLInsert(ps, ps->size, x);
}
//尾删
void SLPopBack(SL* ps)
{
  //断言
  assert(ps);
  /*// 温柔的检查
  //if (ps->size == 0)
    //return;
  // 暴力的检查
  assert(ps->size > 0);
  //ps->a[ps->size - 1] = 0;
  //这里只要size减减就好了,后面的会覆盖
  ps->size--;*/
  //删除pos位置的值
  SLErase(ps, ps->size - 1);
}
//头插
void SLPushFront(SL* ps, SLDataType x)
{
  //断言
  assert(ps);
  /*//定义最后一个元素
  int end = ps->size - 1;
  //循环
  while (end >= 0)
  {
    ps->a[end + 1] = ps->a[end];
    end--;
  }
  //x赋给最前的数字
  ps->a[0] = x;
  //指向下一个数字
  ps->size++;*/
  //在pos位置插入x
  SLInsert(ps, 0, x);
}
//头删
void SLPopFront(SL* ps)
{
  //断言
  assert(ps);
  /*//断言(指向不能为零)
  assert(ps);
  //指向头前面的那个数字
  int begin = 1;
  //循环
  while (begin < ps->size)
  {
    ps->a[begin - 1] = ps->a[begin];
    begin++;
  }
  ps->size--;*/
  //删除pos位置的值
  SLErase(ps, 0);
}
//返回下标,没有找打返回-1
int SLFind(SL* ps, SLDataType x)
{
  //断言
  assert(ps);
  //遍历
  for (int i = 0; i < ps->size; i++)
  {
    if (ps->a[i] == x)
    {
      return i;
    }
  }
  return -1;
}
//在pos位置插入x
void SLInsert(SL* ps, int pos, SLDataType x)
{
  //断言,这里pos
  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++;
}
//删除pos位置的值
void SLErase(SL* ps, int pos)
{
  //断言
  assert(ps);
  //断言pos
  assert(pos >= 0 && pos < ps->size);
  int begin = pos + 1;
  while (begin < ps->size)
  {
    ps->a[begin - 1] = ps->a[begin];
    ++begin;
  }
  ps->size--;
}
//修改pos位置的信息
void SLModify(SL* ps, int pos, SLDataType x)
{
  //断言
  assert(ps);
  //判断pos
  assert(pos >= 0 && pos < ps->size);
  //直接换
  ps->a[pos] = x;
}

🌟结束语

      今天内容就到这里啦,时间过得很快,大家沉下心来好好学习,会有一定的收获的,大家多多坚持,嘻嘻,成功路上注定孤独,因为坚持的人不多。那请大家举起自己的小说手给博主一键三连,有你们的支持是我最大的动力💞💞💞,回见。

目录
相关文章
|
4月前
|
Java C++ Python
【C++】手撕红黑树
【C++】手撕红黑树
26 1
|
5月前
|
存储 算法 C++
【数据结构与算法】:带你手搓顺序表(C/C++篇)
【数据结构与算法】:带你手搓顺序表(C/C++篇)
【手撕红黑树】
【手撕红黑树】
126 0
手撕红黑树
手撕红黑树
73 0
|
6月前
|
存储 Java C++
手撕单链表
手撕单链表
62 0
|
6月前
|
存储 Java C++
手撕双链表
手撕双链表
49 0
|
6月前
|
搜索推荐
手撕各种排序(中)
手撕各种排序(中)
65 0
|
6月前
|
算法 搜索推荐 索引
手撕各种排序(下)
手撕各种排序(下)
59 0
|
6月前
|
安全 Java C语言
手撕各种排序(上)
手撕各种排序
50 0
|
6月前
|
存储 缓存 算法
手撕无头单链表
手撕无头单链表
34 0