手把手教你怎么写顺序表 2

简介: 手把手教你怎么写顺序表

6.删除顺序表中成员的内容

6.1尾删

这个就很简单了,我们只需要将此时顺序表的成员数量往回拨一位就行。为什么?举个例子,成员中已经有了1,2,3,4,5那么不难得出sz此时是5,指向的是5后面的空间,而当我们把数量往回拨的话,sz就指向了4,那么此时sz就指向了5对应的空间,下次你在再增加内容的时候这个空间就会被自动覆盖掉,同样,打印的话也是根据sz来打印的,会直接略过。唯一需要注意的一点就是,当顺序表的成员为空的时候,也就是没有成员的时候,强行删除的话就会造成越界问题的发生。因为没有成员的时候,sz为0,你对它强行进行删除,那么就会导致sz=-1,下一次再增加元素的时候,就会越界访问。

void seqlist_popback(seqlist* s1)
{
  if (s1->sz == 0)
  {
    printf("顺序表为空,操作失败\n");
    return;
  }
  s1->sz--;
}

6.2头删

头删相对于尾删麻烦一些,我们通过从前往后覆盖的方式将前面的内容覆盖成后面的内容

void seqlist_popfront(seqlist* s1)
{
  if (s1->sz == 0)
  {
    printf("顺序表为空,操作失败\n");
    return;
  }
  int i = 0;
  for (i = 1; i < s1->sz; i++)
  {
    s1->a[i-1] = s1->a[i];//从前往后覆盖
  }
  s1->sz--;
}

同样,我们可以测试一下

7.查找成员

目标很简单,就是查找到目标成员然后打印出来,找不到就打印找不到,通过一次遍历就可以搞定

void seqlist_fine(const seqlist* s1,const SlDateType x)
//查找的目标是x,用const修饰是因为只是查找,不用修改
{
  if (s1->sz == 0)
  {
    printf("顺序表为空,操作失败\n");
    return;
  }
  int i = 0;
  for (i = 0;i<s1->sz; i++)
  {
    if (s1->a[i] == x)//相等意味着找到了
    {
      printf("找到%d了,下标为%d\n",x,i);
      return;
    }
  }
  printf("目标不存在\n");
}

同样可以测试一下

8.修改(替换)

给对应的下标,和被修改的结果,对目标下标的内容进行修改,要注意的是,我们修改下标的范围只能是在成员组中进行修改,什么意思?就是说,我们不能对还没放成员的下标进行修改

void seqlist_modify(seqlist* s1, int pos, const SlDateType x)
{
  if (pos >= s1->sz)
  //当pos=sz时就已经是对还不是成员的空间进行操作了,更别说后面的了
  {
    printf("当前空间还不是成员的一部分,操作失败\n");
    return;
  }
  s1->a[pos] = x;
}

同样可以测试一下

9.插入(在目标位置插入成员)

需要注意的便是,我们插入的范围是多少,很显然0~sz-1都是可以插入的,这里面已经是有内容的了,那么sz可不可以呢?可以,因为在sz这个位置插入就相当于尾插,还有一点需要注意,那便是插入成员,成员的数量是会增加的,那么也就是说,我们一样要在插入前判断是否需要扩容。

void seqlist_insert(seqlist* s1, int pos, const SlDateType x)
{
  if_enough(s1);
  if (pos > s1->sz)//比sz还大,意味着插入的位置会导致连续性被破坏
  {
    printf("插入位置出错,操作失败\n");
    return;
  }
  int i = 0;
  for (i = 0;i<s1->sz-pos; i++)
  {
    s1->a[s1->sz-i] = s1->a[s1->sz-i-1];//从后向前覆盖
  }
  s1->a[pos] = x;
  s1->sz++;
}

测试一下

10.定向删除(将目标位置的成员删除)

有了之前插入的经验,这个就显得很简单,但要注意的一点则是,它的删除范围只能是0~sz-1,sz不被包括在内,因为sz显而易见还不是成员。

void seqlist_erase(seqlist* s1, int pos)
{
  if (pos >= s1->sz)//等于sz时就已经是在删除未被定义的内容了
  {
    printf("删除位置出错,操作失败\n");
    return;
  }
  int i = 0;
  for (i=0;pos+i+1<s1->sz;i++)
  {
    s1->a[pos+i] = s1->a[pos+i+1];//从前向后覆盖
  }
  s1->sz--;
}

测试一下

当我们完成了插入和定向删除,其实之前的头插头删,尾插尾删都可以通过这两个函数来替换,这里就不再一一展示,升级版直接放在全部代码里面。

三、全部代码

1.函数头文件

// SeqList.h
//将所需函数和所需头文件的引用放在一个头文件中,那么在使用的时候就只用引用一个头文件
#pragma once//防止头文件被重复引用
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>//可能要用到的头文件
typedef int SlDateType;
//将int typedef成SlDateType这样就可以区分int和顺序表成员
// 虽然它们的类型本质上都是int但是它们的字面含义已经不同
//当然了,可以把int换成别的类型
//这样子设计其实更多的是为了到时顺序表成员类型想更换直接从这换就全换了,不用一个一个换
typedef struct seqlist
{
  SlDateType* a;
  //创建一个指针类型的顺序表成员数据,为什么是指针?
  //这样做是为了到时能够使用malloc和realloc对空间的大小进行开辟与修改
  //相当于柔性数组
  int sz;//已经存放了多少个成员
  int capacity;//容量大小,以后判定空间是否够用可以通过这个来判定
}seqlist;//将结构体名字命名为seqlist,使用时更加方便
//初始化顺序表
void init_seqlist(seqlist*s1);
//打印顺序表
void print_seqlist(const seqlist* s1);
//尾增
void seqlist_pushback(seqlist* s1, SlDateType x);
//头增
void seqlist_pushfront(seqlist* s1, SlDateType x);
//尾删
void seqlist_popback(seqlist* s1);
//头删
void seqlist_popfront(seqlist* s1);
//查找成员
void seqlist_fine(const seqlist* s1,const SlDateType x);
//修改成员
void seqlist_modify(seqlist* s1, int pos, const SlDateType x);
//插入成员
void seqlist_insert(seqlist* s1, int pos, const SlDateType x);
//删除成员
void seqlist_erase(seqlist* s1, int pos);

2.函数实现

//顺序表.c
#include"顺序表.h"
void init_seqlist(seqlist* s1)//通过指针的形式访问,便能够对内容进行修改
{
  s1->capacity = 3;//将容量大小初始化为3,为了更好地测试到时的扩容效果
  s1->sz = 0;//将成员数量初始化为0,代表着此时没有存放成员
  s1->a = (SlDateType*)malloc(sizeof(SlDateType) * s1->capacity);
  //将顺序表的成员数组大小初始化和容量一样的大小
  if (s1->a == NULL)//开辟失败的话直接退出程序
  {
    exit(-1);
  }
}
void if_enough(seqlist* s1)
{
  if (s1->sz == s1->capacity)
  //当容量和成员个数相当时,显然就已经存满了,需要扩容
  {
    s1->a = realloc(s1->a,sizeof(SlDateType)*s1->capacity*2);
    //将容量扩大到原来容量的两倍
    if (s1->a == NULL)
    {
      perror("if_enough");//错误提示
      return;//中止程序
    }
    s1->capacity *= 2;//扩容成功,容量翻倍
    printf("扩容成功,当前容量为%d\n",s1->capacity);//扩容成功给个提示
  }
}
void print_seqlist(const seqlist* s1)
//将内容打印出来,但内容是不会被改变的,因此用const修饰,避免内容被修改
{
  if (s1->sz == 0)
  {
    printf("顺序表为空,操作失败\n");
    return;
  }
  int i = 0;
  for (i = 0; i < s1->sz; i++)
  {
    printf("%d ", s1->a[i]);//将内容通过循环的方式打印出来
  }
  printf("\n");//打印完所有内容之后最好换行
}
void seqlist_pushback(seqlist*s1,SlDateType x)
{
  //if_enough(s1);
  //s1->a[s1->sz] = x;//在顺序表的最后插入一个数据x
  //s1->sz++;
  seqlist_insert(s1,s1->sz,x);
}
void seqlist_pushfront(seqlist* s1, SlDateType x)
{
  //if_enough(s1);
  //int i = 0;
  //for (i=0;i<s1->sz;i++)//通过循环从后往前覆盖
  //{
  //  s1->a[s1->sz - i] = s1->a[s1->sz-i-1];
  //}
  //s1->a[0] = x;//将首元素替换成x
  //s1->sz++;
  seqlist_insert(s1,0, x);
}
void seqlist_popback(seqlist* s1)
{
  /*if (s1->sz == 0)
  {
    printf("顺序表为空,操作失败\n");
    return;
  }
  s1->sz--;*/
  seqlist_erase(s1,s1->sz-1);
}
void seqlist_popfront(seqlist* s1)
{
  //if (s1->sz == 0)
  //{
  //  printf("顺序表为空,操作失败\n");
  //  return;
  //}
  //int i = 0;
  //for (i = 1; i < s1->sz; i++)
  //{
  //  s1->a[i-1] = s1->a[i];//从前往后覆盖
  //}
  //s1->sz--;
  seqlist_erase(s1,0);
}
void seqlist_fine(const seqlist* s1,const SlDateType x)
//查找的目标是x,用const修饰是因为只是查找,不用修改
{
  if (s1->sz == 0)
  {
    printf("顺序表为空,操作失败\n");
    return;
  }
  int i = 0;
  for (i = 0;i<s1->sz; i++)
  {
    if (s1->a[i] == x)//相等意味着找到了
    {
      printf("找到%d了,下标为%d\n",x,i);
      return;
    }
  }
  printf("目标不存在\n");
}
void seqlist_modify(seqlist* s1, int pos, const SlDateType x)
{
  if (pos >= s1->sz)
  //当pos=sz时就已经是对还不是成员的空间进行操作了,更别说后面的了
  {
    printf("当前空间还不是成员的一部分,操作失败\n");
    return;
  }
  s1->a[pos] = x;
}
void seqlist_insert(seqlist* s1, int pos, const SlDateType x)
{
  if_enough(s1);
  if (pos > s1->sz)//比sz还大,意味着插入的位置会导致连续性被破坏
  {
    printf("插入位置出错,操作失败\n");
    return;
  }
  int i = 0;
  for (i = 0;i<s1->sz-pos; i++)
  {
    s1->a[s1->sz-i] = s1->a[s1->sz-i-1];//从后向前覆盖
  }
  s1->a[pos] = x;
  s1->sz++;
}
void seqlist_erase(seqlist* s1, int pos)
{
  if (pos >= s1->sz)//等于sz时就已经是在删除未被定义的内容了
  {
    printf("删除位置出错,操作失败\n");
    return;
  }
  int i = 0;
  for (i=0;pos+i+1<s1->sz;i++)
  {
    s1->a[pos+i] = s1->a[pos+i+1];//从前向后覆盖
  }
  s1->sz--;
}

好了,今天的分享到这里就结束了,感谢各位友友的来访,祝各位友友前程似锦O(∩_∩)O

相关文章
|
1月前
|
存储
手把手设计C语言版循环队列(力扣622:设计循环队列)
手把手设计C语言版循环队列(力扣622:设计循环队列)
32 0
|
1月前
|
存储
顺序表的基本操作(必学)
顺序表的基本操作
45 0
|
8月前
|
Java
《代码随想录》刷题笔记——链表篇【java实现】
《代码随想录》刷题笔记——链表篇【java实现】
70 0
|
8月前
|
存储 搜索推荐 Java
《代码随想录》刷题笔记——数组篇【java实现】
《代码随想录》刷题笔记——数组篇【java实现】
71 0
|
10月前
|
存储
手把手教你怎么写顺序表 1
手把手教你怎么写顺序表
|
10月前
|
存储
代码随想录训练营 Day03- 链表(上)
代码随想录训练营 Day03- 链表(上)
53 0
|
10月前
代码随想录训练营 Day04 - 链表(下)
代码随想录训练营 Day04 - 链表(下)
35 0
|
存储 Java
一篇文章入门单链表+刷题实践【java实现+详细注释】
一篇文章入门单链表+刷题实践【java实现+详细注释】
10654 2
|
11月前
|
存储 算法
【数据结构与算法】单链表的增删查改(附源码)(下)
【数据结构与算法】单链表的增删查改(附源码)(下)
54 0
|
11月前
|
存储 算法
【数据结构与算法】单链表的增删查改(附源码)(上)
【数据结构与算法】单链表的增删查改(附源码)
67 0