身价过亿的帝都富豪对小码农说顺序表会了吗

简介: 身价过亿的帝都富豪对小码农说顺序表会了吗

文章目录


有幸被富豪赏识,顺序表怎能不会

联动文章 五万字超详细Linux知识点

顺序表

线性表

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

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

image.png

但是今天这篇博客只讲顺序表


顺序表(本质上就是数组)

概念及结构

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

顺序表一般可以分为:

1. 静态顺序表:使用定长数组存储元素。

image.png

#pragma once
//方便改数组的大小
#define N 100
typedef int SLDataType; //这样会很方便修改
//静态顺序表
typedef struct SeqList
{
  SLDataType a[N];
  SLDataType size;//表示数组中存储了多少个数据
}SL;
void SeqListPushBack(SL* ps, SLDataType x);

静态的特点是满了就不让插入, 缺点就是我们不知道给多大的空间合适,给大了浪费,给小了“犯罪”,所以就出现了动态顺序表

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

既然都动态了,那么也就没有空间大小N的必要了,我们用指针即可

image.png

//方便改数组的大小
//#define N 100
typedef int SLDataType; //这样会很方便修改
//动态顺序表
typedef struct SeqList
{
  SLDataType* a;
  int size;//表示数组中存储了多少个数据
  int capacity;//数组实际能存数据的空间容量是多大
}SL;
void SeqListPushBack(SL* ps, SLDataType x);


接口函数(这里教你闭坑,不然有时候你不知道怎么死的(值传递与址传递的区别)

顺序表初始化 SeqListInit
值传递

image.png

这里有一个告诫就是vs13与vs19不同,vs13你sl不初始化也可以跑过去,而vs19sl不初始化是跑不过去的,我把vs19跑不过去的图放在下面

image.png

址传递

既然实参的是不能传给形参,那么我们就把地址传过去

image.png

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


尾插函数SeqListPushBack

image.png

//尾插
void SeqListPushBack(SL* ps, SLDataType x)
{
  if (ps->size == ps->capacity)
  {
    //压根就没有空间    
    //空间满的情况,扩容
    int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
    SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));
    if (tmp == NULL)
    {
      printf("开辟失败\n");//没有开辟成功
      exit(-1);//异常结束
    }
    //成功扩容后
    ps->a = tmp;//把新的地址给他
    ps->capacity = newcapacity;//容量给他
  }
  //空间足够的情况
  ps->a[ps->size] = x;
  ps->size++;
}

但是有时候一直调试去看我们接口写的怎么样,会很浪费时间,所以我们得写个打印函数


顺序表打印函数SeqListPrint

image.png

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

我们做到这一步基本可以看成顺序表起步成功,现在我们需要对顺序表销毁,实际上我们是知道,最后的最后才是顺序表的销毁,但是我们这里可以实现了(你可以可理解成单片机的最小系统或者丐版微星一个意思)

顺序表销毁函数SeqListDestory

image.png

//顺序表销毁
void seqListDestory(SL* ps)//就是释放内存,防止内存溢出
{
  free(ps->a);
  ps->a = NULL;
  ps->capacity = ps->size = 0;
}

最小系统板好了我们就一个一个加模块


尾删函数SeqListPopBack

温柔

image.png

//尾删
void SeqListPopBack(SL* ps)
{
  //温柔做法
  if (ps->size > 0)
  {
    ps->size--;
  }
}

粗暴(我一个大男人比较喜欢粗暴一点的做法,直接了当)

image.png

//尾删
void SeqListPopBack(SL* ps)
{
  温柔做法
  //if (ps->size > 0)
  //{
  //  ps->size--;
  //}
  //粗暴
  assert(ps->size > 0);//断言不为真直接报错,管你不轻
  ps->size--;
}

在写头插之前,我们思考一下,你要插入,肯定要考虑到是否需要扩容,那么就与之前尾插里面的扩容重了,所以可以抽取出来单独写一个函数

顺序表检查容量函数SeqListCheckCapacity

image.png

//顺序表检查容量
void SeqListCheckCapacity(SL* ps)
{
  if (ps->size == ps->capacity)
  {
    //压根就没有空间    
    //空间满的情况,扩容
    int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
    SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));
    if (tmp == NULL)
    {
      printf("开辟失败\n");//没有开辟成功
      exit(-1);//异常结束
    }
    //成功扩容后
    ps->a = tmp;//把新的地址给他
    ps->capacity = newcapacity;//容量给他
  }
}

然后用那个检查容量就可以很轻松的扩容了

头插函数SeqListPushFront

image.png

//头插
void SeqListPushFront(SL* ps, SLDataType x)
{
  //检查增容
  SeqListCheckCapacity(ps);
  //挪动数据
  int end = ps->size - 1;
  while (end>=0)
  {
    ps->a[end + 1] = ps->a[end];
    end--;
  }
  ps->a[0] = x;
  ps->size++;
}

头删SeqListPopFront

image.png

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

顺序表查找函数SeqListFind

image.png

//顺序表查找函数
int SeqListFind(SL* ps, SLDataType x)
{
  int i = 0;
  for (i = 0; i < ps->size; i++)
  {
    if (ps->a[i] == x)
      return i;
  }
  return -1;
}

顺序表插入函数SeqListInsert

image.png

//顺序表插入函数
void SeqListInsert(SL* ps, int pos, SLDataType x)
{
  //断言不在范围内直接结束
  assert(pos>=0 && pos<=ps->size);
  //检查扩容
  SeqListCheckCapacity(ps);
  //挪动数据
  int end = ps->size - 1;
  while (pos<=end)
  {
    ps->a[end + 1] = ps->a[end];
    end--;
  }
  //然后再把数据给当前位置
  ps->a[pos] = x;
  ps->size++;
}

所以头插尾插就不需要写了,直接调用插入函数即可

顺序表删除函数SeqListErase

image.png

//顺序表删除函数
void SeqListErase(SL* ps, int pos)
{
  //断言不在范围内直接结束
  assert(pos >= 0 && pos < ps->size);
  //删除不需要考虑扩容,直接挪动数据 
  int begin = pos;
  while (begin+1<ps->size)
  {
    ps->a[begin] = ps->a[begin + 1];
    begin++;
  }
  ps->size--;
}

所以头删尾删也就可以 复用掉

练习题

例1移除元素

image.png

image.png

我们先分析一下题,他对空间复杂度是有要求的,对时间复杂度没有什么要求

image.png

int removeElement(int* nums, int numsSize, int val){
    int i = 0;
    int* cur = nums;
    for(i = 0;i<numsSize;i++)
    {
        if(val ^ nums[i])
        {
           *cur++ = nums[i];            
        }
    }
    return cur-nums;
}

例2删除有序数组中的重复项

image.png

image.png

我们不能空看我们得画图解决,题目直接把空间定死,不会给你开额外的数组了,也就只能多指针解决

脑内模拟一番,一个定位指针,两个游标指针,应该可以解决

image.png

int removeDuplicates(int* nums, int numsSize){
    if(numsSize == 0)//空数组跳出
    return 0;
    int* cur = nums;//定位指针
    int* head = nums;//游标头指针
    int* tail = nums+1;//游标尾指针
    while(tail<nums+numsSize)
    {
        if(*head == *tail)
        {
            tail++;
        }
        else
        {
            *cur = *head;
            cur++;
            head = tail;
            tail++;
        }
    }
    *cur = *head;//最后一个不管等不等都强制赋值
    cur++;
    return (cur-nums);
}

例3合并两个有序数组

image.png

image.png

image.png

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
    int* p1 = nums1+m-1;
    int* p2 = nums2+n-1;
    int* cur = nums1+m+n-1;
    while(p1>=nums1 && p2>=nums2)
    {
        *cur-- = *p1>*p2 ? *p1-- : *p2--;//三目运算符
    }
    while(p2>=nums2)
    {
        *cur-- = *p2--;
    }
}

联动文章 五万字超详细Linux知识点


目录
相关文章
|
测试技术
蓝桥 晚会节目单 (线段树)
蓝桥 晚会节目单 (线段树)
|
算法 搜索推荐
2015年华科834复试笔试题
2015年华科834复试笔试题
|
算法 调度 数据库
2016年华科834复试笔试题
2016年华科834复试笔试题
|
存储 人工智能 算法
【蓝桥杯集训·最后一次周赛】AcWing 第 97 场周赛
文章目录 第一题 AcWing 4944. 热身计算 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第二题 AcWing 4945. 比大小 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第三题 AcWing 4946. 叶子节点 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解
134 0
|
JavaScript BI
【蓝桥杯集训·周赛】AcWing 第96场周赛
文章目录 第一题 AcWing 4876. 完美数 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第二题 AcWing 4877. 最大价值 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第三题 AcWing 4878. 维护数组 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解
92 0
|
存储 机器学习/深度学习 人工智能
【蓝桥杯集训·周赛】AcWing 第 95 场周赛
文章目录 第一题 AcWing 4873. 简单计算 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第二题 AcWing 4874. 约数 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第三题 AcWing 4875. 整数游戏 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解
114 0
|
存储 机器学习/深度学习 人工智能
【蓝桥杯集训·周赛】AcWing 第94场周赛
文章目录 第一题 AcWing 4870. 装物品 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第二题 AcWing 4871. 最早时刻 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第三题 AcWing 4872. 最短路之和 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解
78 0
|
存储
【蓝桥杯集训·周赛】AcWing 第92场周赛
文章目录 第一题 AcWing 4864. 多边形 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第二题 AcWing 4865. 有效类型 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第三题 AcWing 4866. 最大数量 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解
126 0
|
存储 人工智能 BI
【蓝桥杯集训·周赛】AcWing 第91场周赛
文章目录 第一题 AcWing 4861. 构造数列 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第二题 AcWing 4862. 浇花 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第三题 AcWing 4861. 构造数列 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解
86 0
|
存储 人工智能
【蓝桥杯集训·周赛】AcWing 第93场周赛
文章目录 第一题 AcWing 4867. 整除数 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第二题 AcWing 4868. 数字替换 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第三题 AcWing 4869. 异或值 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解
105 0
下一篇
DataWorks