【数据结构】顺序表(长期维护)

简介: 【数据结构】顺序表(长期维护)

1.顺序表

顺序表:使用一段连续的物理地址依次存储数据元素的线性结构,通常底层是数组,并且有着增删查改的接口的数据结构。

知识拓展:线性表

线性表,我们规定逻辑结构上是线性的,物理结构上不一定是线性的数据结构称为线性表。

线性表包括:顺序表、链表、栈、队列、字符串…

2.静态与动态

//静态顺序表
typedef int int_n;
typedef struct seqlist
{
  int_n arr_n[100];
  int size_n;
  int capacity_n;
};
//动态顺序表
typedef int int_t;
typedef struct SeqList
{
  int_t* arr;
  int size;
  int capacity;
}SL;

思考:静态顺序表与动态顺序表的优劣在哪里?

动态顺序表更加灵活一些。

结论:由于动态顺序表的灵活优势,因而首选动态顺序表。

3.动态顺序表的实现

详细思路请点击link链接,LINK

下面是一些功能函数声明和顺序表原型都放在.h文件中。

顺序表是由一个原型和一系列接口(功能)组成的:因而我们首先升级一个数组为动态顺序表原型:

//动态顺序表
typedef int int_t;
typedef struct SeqList
{
  int_t* arr;
  int size;
  int capacity;
}SL;

实现各种顺序表的功能接口:

//顺序表初始化的功能
void SLinit(SL* psl);
//顺序表尾插
void SLpushback(SL* psl,int_t n);
//顺序表头插
void SLpushfront(SL* psl,int_t n);
//顺序表中间插
void SLinnert(SL* psl, int pos, int_t n);
//顺序表打印
void SLprint(SL* psl);
//顺序表尾删
void SLpopback(SL* psl);
//顺序表头删
void SLpopfront(SL* psl);
//顺序表中间删
void SLpopinnert(SL* psl,int pos);
• 16

下面是具体实现一些函数功能接口:

#include"SeqList.h"
void SLPrintArr(SL* psl)
{
  for (int i = 0; i < psl->size; i++)
  {
    printf("%d ", *(psl->arr + i));
  }
  printf("\n");
}
void SLInit(SL* psl)
{
  assert(psl);//思考1:这里为什么需要断言?
  psl->arr = NULL;
  psl->capacity = 0;
  psl->size = 0;
}
void SLCheckCapacity(SL* psl)
{
  if (psl->capacity == psl->size)//已满,扩容
  {
    int newcapacity = psl->capacity == 0 ? 4 : 2 * psl->capacity;
    SLDataType* tarr = (SLDataType*)realloc(psl->arr, sizeof(SLDataType) * newcapacity);//思考:realloc的本地扩容与异地扩容分析
    if (tarr == NULL)
    {
      perror("realloc fail");
      exit(-1);
    }
    psl->arr = tarr;
    psl->capacity = newcapacity;
  }
}
void SLDestroy(SL* psl)
{
  assert(psl);
  free(psl->arr);
  psl->arr = NULL;
  psl->capacity = psl->size = 0;
}
void SLPushBack(SL* psl, SLDataType x)
{
  assert(psl);
  SLCheckCapacity(psl);
  psl->arr[psl->size++] = x;
}
void SLPushFront(SL* psl, SLDataType x)
{
  assert(psl);
  SLCheckCapacity(psl);
  int end = psl->size - 1;
  while (end >= 0)
  {
    psl->arr[end + 1] = psl->arr[end];
    end--;
  }
  psl->arr[0] = x;
  psl->size++;
}
void SLPopBack(SL* psl)//思考2:在删除元素的时候,需要及时free吗?
{
  assert(psl);
  assert(psl->size > 0);
  psl->size--;
}
void SLPopFront(SL* psl)
{
  assert(psl);
  assert(psl->size>1);//假设没有 思考3:过度删除之后,进行头插
  int start = 1;
  while (start < psl->size)
  {
    psl->arr[start-1] = psl->arr[start];
    start++;
  }
  psl->size--;
}
void SLInsert(SL* psl,int pos, SLDataType x)
{
  assert(psl);
  assert(pos >= 0 && pos <= psl->size);
  SLCheckCapacity(psl);
  int end = psl->size - 1;
  while (end >= pos)
  {
    psl->arr[end+1] = psl->arr[end];
    end--;
  }
  psl->arr[pos] = x;
  psl->size++;
}
void SLErase(SL* psl, int pos)
{
  assert(psl);
  assert(psl->size > 0);
  assert(pos >= 0 && pos < psl->size);
  int end = pos + 1;
  while (end < psl->size)
  {
    psl->arr[end-1] = psl->arr[end];
    end++;
  }
  psl->size--;
}
SLDataType* SLFind(SL* psl, int num)
{
  assert(psl);
  assert(psl->size > 0);
  for (int i = 0; i < psl->size; i++)
  {
    if (psl->arr[i] == num)
    {
      return &(psl->arr[i]);
    }
  }
  printf("未查找到!\n");
  return NULL;
}

思考1:因为顺序表的实现是默认为非空指针的,所以需要assert检查一下是否为空指针。

思考2:不需要,因为空间释放不支持分期付款

思考3:这是一种错误情景:过度删除之后在进行头插,这种时候数据出错误,但是编译器并不会报错,size可能会变成负数。

那为什么没有崩溃?因为没有越界访问。

反思:当前出现的错误可能是之前出现的错误,为自己埋下的坑。

解决有两种方法:一是if检查二是assert断言一下。

下面是测试代码源文件内容(在test.c文件中):

#define _CRT_SECURE_NO_WARNINGS 1
#include"SeqList.h"
int main()
{
  SL sl;
  SLinit(&sl);
  SLpushback(&sl,1);
  SLpushfront(&sl, 1);
  SLpushfront(&sl, 1);
  SLpushfront(&sl, 1);
  SLpushfront(&sl, 1);
  SLprint(&sl);
  SLinnert(&sl, 1, 3);
  SLprint(&sl);
  
  SLpopback(&sl);
  SLprint(&sl);
  SLpopfront(&sl);
  SLprint(&sl);
  SLpopinnert(&sl,3);
  SLprint(&sl);
  return 0;
}

4.相关练习题

三道题目的思路方法预览:

1.移除元素

LINK

//三条思路
//1.传统的覆盖
//2.开新数组
//3.双指针
int removeElement(int* nums, int numsSize, int val) {
    int i = 0;
    int p1 = 0;//探路者
    int p2 = 0;//守家者
    for(i = 0;i<numsSize;i++)
    {
        if(nums[p1]==val)
        {
            p1++;
        }
        else
        {
            nums[p2++] = nums[p1++];
        }
    }
    return p2;
}

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

LINK

int removeDuplicates(int* nums, int numsSize) {
    int src = 1;
    int dest = 0;
    while(src<numsSize)
    {
        if(nums[src]==nums[dest])
        {
            src++;
        }
        else
        {
            dest++;
            nums[dest] = nums[src];
            src++;
        }
    }
    return dest+1;
}

3.合并两个有序数组

LINK

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) {
    int i1 = m - 1;
    int i2 = n - 1;
    int k = nums1Size - 1;
    while(i1>=0 && i2>=0)
    {
        if(nums1[i1]>nums2[i2])
        {
            nums1[k--] = nums1[i1--];
        }
        else
        {
            nums1[k--] = nums2[i2--];
        }
    }
    while(i2>=0)
    {
            nums1[k--] = nums2[i2--];
    }
    
}

EOF

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