赞
踩
目录
线性表(linearlist)是n个具有相同特性的数据元素的有限序列。线性表在逻辑结构是线性的,但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。
顺序表(Sequential List)是一种基本的数据结构,它通过一组连续的存储单元来存储具有相同类型的数据元素。
与数组的区别:
- 大小变化:数组的大小在创建时确定,之后不能改变;而顺序表的大小可以动态变化。
- 扩容机制:数组通常不支持直接扩容;顺序表在需要时可以通过重新分配内存空间来实现扩容。
- 使用场景:数组适用于元素数量固定不变或变化不大的场景;顺序表则更适用于元素数量需要动态变化的场景。
(顺序表的底层结构是数组,对数组的封装,实现了常用的增删改查等接口)
顺序表逻辑结构是线性的,物理结构也是连续的。
特点:随机访问快、插入删除慢(需要移动元素)、存储空间固定或动态扩展 。
顺序表是一个存储结构,因此什么数据类型都可以存储。将int类型的名字替换成SLDataTYpe,后续如果向存储别的类型,如char,short,结构体等类型时,只需要将int修改为char,short,结构体等类型,使得操作更加简化。
- typedef int SLdatetype;
- #define N 100
- typedef struct SeqList
- {
- SLdatetype arr[N];//定长数组:开辟空间大小为100的数组
- int size;//指有效数据的个数
- }SL;
概念:使用定长数组存储元素
缺陷:
固定大小限制
内存利用效率低
插入/删除困难
数据大小限制
难以管理
空间给少了溢出,给多了造成空间浪费。实际应用中出现较少
- typedef struct Seqlist
- {
- SldateType* arr;//存储数据的底层结构
- int capacity;//空间容量
- int size;//有效数据的个数
- }SL;
概念:动态顺序表(Dynamic Array)是一种能够根据需要动态调整大小的数组结构,通常用于存储元素集合,并支持高效的随机访问和动态增删操作。
缺陷:
内存浪费
插入/删除效率低
容量调整耗时
不适合大对象存储
频繁扩容导致性能下降
准备工作:
创建三个代码文件:
1)SeqListc.h(头文件)—— 接口声明文件
2) SeqList.c(源文件)——接口实现文件
3) test.c(测试文件)——功能测试文件
- void SlInit(SL *ps)
- {
- assert(ps != NULL);//判断ps是否为空
- ps->arr = NULL;
- ps->capacity = ps->size = 0;
- }
- void Sldestory(SL* ps)
- {
- assert(ps != NULL);//判断ps是否为空
- ps->arr = NULL;
- ps->capacity = ps->size = 0;
- }
中间/头部的插入删除,时间复杂度为O(n)
准备知识:
顺序表的头插和尾插
1)空间足够,直接插入
2)空间不够,扩容
扩容的原则:1)一次扩容一个空间
2)一次扩容固定的大小
3)成倍数地增加 (推荐:按倍数增加效率高,空间浪费相对较少)————动态内存管理
(三者都是分配内存,都是stdlib.h库里的函数(多次分配会造成程序效率低下)
malloc :用于动态分配指定字节数的内存空间。
calloc : 函数用于动态分配指定数目和大小的内存空间,并将内存初始化为零。
realloc:函数用于重新分配之前分配的内存块大小。
扩容的完整代码:
一般采用1.5倍或2倍进行扩容(1.5倍或2倍扩容策略在内存管理中是一种折中方案,能够在保证性能的同时,有效地管理内存和提高程序运行效率。)
- void SlCheckCapacity(SL *ps)
- {
- if (ps->size == ps->capacity) {
- int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;//三目运算符(如果是0则赋值为4,否则capacity*2)
- int* tmp = (SldateType*)realloc(ps->arr, newcapacity * sizeof(SldateType));//空间申请(注意开辟的是字节数)
- //判断申请空间成功
- if (tmp == NULL)
- {
- perror("realloc fail");
- exit(1);
- }
- //free(ps->arr);//为什么注释掉:因为realloc已释放arr原来的空间,无需再次释放
- ps->arr = tmp;
- ps->capacity = newcapacity;
- }
- }
- void pushBack(SL* ps, SldateType x)//将x插入顺序表的尾部
- {
- //断言
- assert(ps != NULL);//如果为NULL直接报错
- SlCheckCapacity(ps);//判断是否需要扩容
- ps->arr[ps->size] = x;//尾插
- ps->size++;//有效数据个数 + 1
- }
- void pushFront(SL* ps, SldateType x)//将x插入顺序表的头部
- {
- assert(ps != NULL);//如果为NULL直接报错
- SlCheckCapacity(ps);//判断是否需要扩容
- //旧数据向后挪一位
- for (int i = ps->size; i > 0; i--)
- {
- ps->arr[i] = ps->arr[i - 1];
- }
- ps->arr[0] = x;//头插
- ps->size++;//有效数据个数 + 1
- }
pos为插入的位置。用assert限定插入的位置,防止出现负数或者过大的数。
- void Insert(SL* ps,int pos,SldateType x)
- {
- assert(ps != NULL);
- assert(pos >= 0 && pos <= ps->size);//检查pos下标的合法性
- SlCheckCapacity(ps);//判断是否需要扩容
- for (int i = ps->size; i > pos; i--)
- {
- ps->arr[i] = ps->arr[i - 1];
- }
- ps->arr[pos] = x;//指定位置插入元素x
- ps->size++;//有效数据个数 + 1
- }
- void PopFront(SL* ps)
- {
- assert(ps != NULL);
- assert(ps->size);
- //不为空执行挪动
- for (int i = 0; i <ps->size-1; i++)
- {
- ps->arr[i] = ps->arr[i + 1];
- }
- ps->size--;//有效数据个数 - 1
- }
- void PopBack(SL* ps)
- {
- assert(ps != NULL);
- assert(ps->size);
- ps->size--; //有效数据个数 - 1
- }
pos为删除的位置。用assert限定插入的位置,防止出现负数或者过大的数。
- void Erase(SL* ps, int pos)
- {
- assert(ps != NULL);//如果为NULL直接报错
- assert(ps->size);//顺序表不能为空
- assert(pos >= 0 && pos < ps->size);//检查pos下标的合法性
- for (int i = pos; i < ps->size; i++)
- {
- ps->arr[i] = ps->arr[i + 1];
- }
- ps->size--;//有效数据个数 - 1
- }
- int Find(SL* ps,SldateType x)//查找指定元素在顺序表的位置
- {
- for (int i = 0; i < ps->size; i++)
- {
- if (ps->arr[i] == x) return i;//找到了返回pos
- }
- return -1;//没找到返回-1
- }
- void SlPrint(SL* ps)
- {
- for (int i = 0; i < ps->size; i++)//打印顺序表
- printf("%d ", ps->arr[i]);
- printf("\n");
- }
.h头文件
- #pragma once//防止头文件被二次引用
- #include<stdio.h>
- #include<stdlib.h> /*realloc*/
- #include<assert.h> /*assert*/
-
- typedef int SldateType;
-
- //动态顺序表
-
- typedef struct Seqlist
- {
- SldateType* arr;//存储数据的底层结构
- int capacity;//空间容量
- int size;//有效数据的个数
- }SL;
- //初始化
- void SlInit(SL *ps);
-
- //销毁
- void Sldestory(SL* ps);
-
- //打印顺序表
- void SlPrint(SL* ps);//保持接口一致性
-
- //顺序表的头插和尾插
- void pushFront(SL* ps, SldateType x);//将x插入顺序表的头部
-
- //将x插入顺序表的尾部
- void pushBack(SL* ps, SldateType x);
-
- //删除顺序表的最后一个数
- void PopBack(SL* ps);
-
- //删除顺序表的第一个数
- void PopFront(SL* ps);
-
- //从指定位置pos之前插入元素x
- void Insert(SL* ps, int pos, SldateType x);
-
- //从指定位置pos删除元素
- void Erase(SL* ps, int pos);
-
- //查找元素x在顺序表的下标
- int Find(SL* ps, SldateType x);
.c文件
- #include"SeqList.h"
-
- //实现接口
- //初始化
- void SlInit(SL *ps)
- {
- assert(ps != NULL);//判断ps是否为空
- ps->arr = NULL;
- ps->capacity = ps->size = 0;
- }
-
- //销毁
- void Sldestory(SL* ps)
- {
- assert(ps != NULL);//判断ps是否为空
- ps->arr = NULL;
- ps->capacity = ps->size = 0;
- }
-
- void SlCheckCapacity(SL *ps)
- {
- if (ps->size == ps->capacity) {
- int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;//三目运算符(如果是0则赋值为4,否则capacity*2)
- int* tmp = (SldateType*)realloc(ps->arr, newcapacity * sizeof(SldateType));//空间申请(注意开辟的是字节数)
- //判断申请空间成功
- if (tmp == NULL)
- {
- perror("realloc fail");
- exit(1);
- }
- //free(ps->arr);//为什么注释掉:因为realloc已释放arr原来的空间,无需再次释放
- ps->arr = tmp;
- ps->capacity = newcapacity;
- }
- }
- void pushBack(SL* ps, SldateType x)//将x插入顺序表的尾部
- {
- //断言
- assert(ps != NULL);//如果为NULL直接报错
- SlCheckCapacity(ps);//判断是否需要扩容
- ps->arr[ps->size] = x;
- ps->size++;
- }
-
- void pushFront(SL* ps, SldateType x)//将x插入顺序表的头部
- {
- assert(ps != NULL);//如果为NULL直接报错
- SlCheckCapacity(ps);//判断是否需要扩容
- //旧数据向后挪一位
- for (int i = ps->size; i > 0; i--)
- {
- ps->arr[i] = ps->arr[i - 1];
- }
- ps->arr[0] = x;//头插数据
- ps->size++;//有效数据个数 + 1
- }
-
- void SlPrint(SL* ps)
- {
- for (int i = 0; i < ps->size; i++)//打印顺序表
- printf("%d ", ps->arr[i]);
- printf("\n");
- }
-
- void PopBack(SL* ps)
- {
- assert(ps != NULL);
- assert(ps->size);
- ps->size--; //有效数据个数 - 1
- }
-
- void PopFront(SL* ps)
- {
- assert(ps != NULL);
- assert(ps->size);
- //不为空执行挪动
- for (int i = 0; i <ps->size-1; i++)
- {
- ps->arr[i] = ps->arr[i + 1];
- }
- ps->size--;//有效数据个数 - 1
- }
-
- void Insert(SL* ps,int pos,SldateType x)
- {
- assert(ps != NULL);
- assert(pos >= 0 && pos <= ps->size);
- SlCheckCapacity(ps);//判断是否需要扩容
- for (int i = ps->size; i > pos; i--)
- {
- ps->arr[i] = ps->arr[i - 1];
- }
- ps->arr[pos] = x;
- ps->size++;
- }
-
- void Erase(SL* ps, int pos)
- {
- assert(ps != NULL);
- assert(ps->size);
- assert(pos >= 0 && pos < ps->size);
- for (int i = pos; i < ps->size; i++)
- {
- ps->arr[i] = ps->arr[i + 1];
- }
- ps->size--;//有效数据个数 - 1
- }
-
- int Find(SL* ps,SldateType x)//查找指定元素在顺序表的位置
- {
- for (int i = 0; i < ps->size; i++)
- {
- if (ps->arr[i] == x) return i;//找到了返回pos
- }
- return -1;//没找到返回-1
- }
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。