顺序表 的认识以及动态顺序表的实现

文章详细介绍了线性表的概念,特别是顺序表的特性,包括它的优点(如支持随机访问)和缺点(如插入删除效率低,可能需要扩容)。接着,文章提供了静态和动态顺序表的示例代码,展示了如何初始化、插入、删除和扩容等操作,并强调了在实现过程中需要注意的边界条件和内存管理问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1 线性表

2 顺序表

2.1 缺点

2.2 优点

2.3 示例

2.3.1 静态顺序表

2.3.2 动态顺序表

2.3.3 接口函数

2.3.3.1 尾删数据

2.3.3.2 头插数据

2.3.3.3 头删数据

3 动态顺序表的实现

3.1 顺序表的创建

3.2 接口函数的声明

3.3 初始化

3.4 销毁顺序表

3.5 找x,找到返回下标,未找到返回-1

3.6 指定pos位置插入x

3.7 删除pos位置的数据

3.8 尾插数据

3.9 打印顺序表

3.10 检查并扩容

3.11 尾删数据

3.12 头插数据

3.13 头删数据


1 线性表

线性表是n个具有相同特性的数据元素的有限序列。

常见的有:顺序表、链表、栈、队列、字符串....

特点:

  • 线性表在逻辑上是线性结构的,即一条连续的直线

  • 但在物理结构上不一定是连续的,其在物理存储时,通常以数组和链式结构的形式存储


2 顺序表

使用一段地址连续的存储单元依次存储数据元素的线性结构

顺序表就是数组,但在数组基础上,要求数据从头开始且连续存储,不能跳跃或间隔


2.1 缺点

  • 空间不够需要扩容,而扩容会付出一定代价

    原地扩容

在这里插入图片描述

还是原地址,代价低,至少不需要拷贝原数据

异地扩容

在这里插入图片描述

已经改变

  • 避免频繁扩容:平常空间满了扩2倍,可能会导致一定的空间浪费 如100->200,但实际我们只需要120个空间,浪费80个

  • 要求数据从头开始连续存储,那么我们在头部或中间位置插入数据需要挪动数据,效率低

2.2 优点

  • 支持随机访问

  • 对于有些算法,需要结构支持随机访问,如二分查找,优化后的快排等

2.3 示例

SeqList.h 头文件

2.3.1 静态顺序表

 #define N 1000
 typedef int SLDataType;    // 以后需要存储不同类型的数据,可以直接修改
 ​
 typedef struct SeqList
 {
     SLDataType a[N];
     int size; // 表示数组中存储了多少个数据
 }SL;
 ​
 //    接口函数 - 函数名是根据STL风格
 void SeqListInit(SL* ps);    //    初始化数组
 //    静态:容量给小则不够用,给大则浪费空间
 void SeqListPushBack(SL* ps, SLDataType x);    //尾插
 void SeqListPopBack(SL* ps);                //尾删
 void SeqListPushFront(SL* ps, SLDataType x);//头插
 void SeqListPopFront(SL* ps);                //头删

2.3.2 动态顺序表

 typedef int SLDataType;    
 ​
 //    动态顺序表
 typedef struct SeqList
 {
     SLDataType* a;
     int size; 
     int capacity;    // 数组实际能存储的空间容量是多少个
 }SL;
 ​
 ​
 void SeqListInit(SL *ps);    // 形参 是实参的临时拷贝,不会影响实参 - 传值操作
     //           所以传地址
 void SeqListPushBack(SL* ps, SLDataType x);    
 void SeqListPopBack(SL* ps);                
 void SeqListPushFront(SL* ps, SLDataType x);
 void SeqListPopFront(SL* ps);           

SeqList.c源文件

 #pragma once
 #include "SeqList.h"
 ​
 void SeqListInit(SL*ps)
 {
     ps->a = NULL;
     ps->size = ps->capacity = 0;
 }
 void SeqListPushBack(SL* ps, SLDataType x)
 {
     //  如果没有空间(0个)或空间不足(满了)
     if (ps->size == ps->capacity)
     {
         int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
         //  三目操作符 是否等于0,是给4,否则给2倍原空间
         SLDataType* tmp = (SLDataType * )realloc(ps->a, sizeof(SLDataType) * newcapacity);
         //    开辟空间
         if (tmp == NULL)
         {
             printf("realloc fail\n");
             exit(-1);
         }
         ps->a = tmp;    //    开辟的空间给结构体
         ps->capacity = newcapacity;// 开辟的大小给原大小
     }
     ps->a[ps->size] = x; // 要传的值给结构体
     ps->size++;
 }
 ​
 void SeqListPushBack(SL* ps, SLDataType x);
 void SeqListPopBack(SL* ps);
 void SeqListPushFront(SL* ps, SLDataType x);
 void SeqListPopFront(SL* ps);

Source.c文件

 #include"SeqList.h"
 ​
 void TestSeqList1() 
 {
     SL sl;
     SeqListInit(&sl);
 }
 int main()
 {
     TestSeqList1();
     return 0;
 }

注意:传结构体不能传值,必须传址,否则无法修改里面内容(形参是实参的临时拷贝,形参的改变不影响实参)


2.3.3 接口函数

2.3.3.1 尾删数据

在这里插入图片描述

注意此处,未加判断条件size–将可以为负值(-1,-2…)

在这里插入图片描述

而在–负数后,再增加数据,会造成越界访问

在这里插入图片描述在这里插入图片描述

在销毁时会报错

纵上

在这里插入图片描述

  • 方法1:加上判断条件,空间大于0才可

  • 方法2:断言,小于等于0直接报错

2.3.3.2 头插数据

在这里插入图片描述

数据向挪动,空出前面的位置

在这里插入图片描述

同尾删数据,未判断大小,若添加数据过多大于有效空间大小,将造成越界访问,报错

在这里插入图片描述在这里插入图片描述

多处用到扩容,这里直接封装成函数

在这里插入图片描述在这里插入图片描述

若空间满了扩容

2.3.3.3 头删数据

和尾插数据类似

第二个数据开始一个一个放上去 在这里插入图片描述在这里插入图片描述

3 动态顺序表的实现

3.1 顺序表的创建

 typedef int SLDataType;    
 typedef struct SeqList
 {
     SLDataType* a;
     int size; 
     int capacity;    // 数组实际能存储的空间容量是多少个
 }SL;

3.2 接口函数的声明

 void SeqListInit(SL *ps);        // 初始化顺序表
     // 形参 是实参的临时拷贝,不会影响实参 - 传值操作
     //           所以传地址
 void SeqListDestory(SL* ps);    // 使用完后销毁,防止内存泄露
 void SeqListCheckCapacity(SL* ps);    //    检查容量+扩容
 void SeqListPrint(SL* ps);            //    打印数据
 void SeqListPushBack(SL* ps, SLDataType x);    //    尾插
 void SeqListPopBack(SL* ps);    // 尾删            
 void SeqListPushFront(SL* ps, SLDataType x); // 头插
 void SeqListPopFront(SL* ps);                //  头删
 int SeqListFind(SL* ps, SLDataType x);    // 找到x返回下标,未找到返回-1
 void SeqListInsert(SL* ps, int pos, SLDataType x);    // 指定pos位置插入x
 void SeqListErase(SL* ps, int pos);        //    删除pos位置的数据

3.3 初始化

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

3.4 销毁顺序表

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

3.5 找x,找到返回下标,未找到返回-1

 int SeqListFind(SL* ps, SLDataType x)
 {
     int begin = 0;
     while (begin++ <= ps->size)
     {
         if (ps->a[begin] == x)
             return begin;
     }
     return -1;
 }

3.6 指定pos位置插入x

 void SeqListInsert(SL* ps, int pos, SLDataType x)
 {
     assert(pos <= ps->size && pos >= 0);
     // 判断+扩容
     SeqListCheckCapacity(ps);
     // 挪动数据,从后往前
     int end = ps->size - 1;
     while (end >= pos)
     {
         ps->a[end + 1] = ps->a[end];
         end--;
     }
     // 插入数据
     ps->a[pos] = x;
     ps->size++;
 }

3.7 删除pos位置的数据

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

3.8 尾插数据

 void SeqListPushBack(SL* ps, SLDataType x)
 {
     SeqListInsert(ps, ps->size, x);
 }

3.9 打印顺序表

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

3.10 检查并扩容

 void SeqListCheckCapacity(SL* ps)
 {
     //  如果没有空间(0个)或空间不足(满了)
     if (ps->size == ps->capacity)
     {
         int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
         //  三目操作符 是否等于0,是给4,否则给2倍原空间
         SLDataType* tmp = (SLDataType*)realloc(ps->a, sizeof(SLDataType) * newcapacity);
         //    开辟空间
         if (tmp == NULL)
         {
             printf("realloc fail\n");
             exit(-1);    // 异常终止程序
         }
         ps->a = tmp;    //    开辟的空间给结构体
         ps->capacity = newcapacity;// 开辟的大小给原大小
     }
 }

3.11 尾删数据

 void SeqListPopBack(SL* ps)
 {
     SeqListErase(ps, ps->size-1);
 }

3.12 头插数据

 void SeqListPushFront(SL* ps, SLDataType x)
 {
     SeqListInsert(ps, 0, x);
 }

3.13 头删数据

void SeqListPopFront(SL* ps)
{
    SeqListErase(ps, 0);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值