线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串…。线性表在逻辑上是线性结构,也就是说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式的结构的形式存储。
线性表一般用于存储有顺序关系的数列。最典型的例子就是为队列(先进先出)、栈(先进后出)。
顺序表一般是用一段物理地址连续的存储单位依次存储元素的线性结构,一般情况下采用数组存储。在数组上完成增删查改。
//静态顺序表
#define n 10
typedef int SLDataType;
typedef struct SeqList
{
//定长数组
SLDataType arr[n];
//有效数据的个数
int size;
}SeqList;
静态顺序表最大的缺陷就是,当数据存放满的时候就需要手动去增加,如果程序写成这样那会被骂死的,所以顺序有引入了动态顺序表。
//动态顺序表
typedef int SLDataType;
typedef struct SeqList
{
//指向动态开辟的数组
SLDataType* arr;
//有效数据的个数
int size;
//容量空间的大小
int capacity;
}SeqList;
当数组的空间满了,程序就会自动的扩容,这样相较与静态顺序表来说就灵活了很多,但是还是会造成空间浪费,后面我会讲一个更好的结构。
下面我们来用动态顺序表来实现对数据的增删查改。因为静态顺序表实用性不怎么强我这里就不演示了,直接开干动态顺序表:
//顺序表的初始化
void SeqListInit(SeqList* ps)
{
//断言传过来的指针是否为空
assert(ps);
//首先把指向数组的指针置空
ps->arr = NULL;
//在把有效数据个数置空
ps->size = 0;
//给容量付个初始值
ps->capacity = 0;
}
// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList* ps)
{
//对指针进行断言
assert(ps);
//判断空间是否为空或者数据满了
if (ps->size==ps->capacity)
{
//定义一个变量来接收容量的值
//当容量的值为0的时候直接赋值为4,不为空的时候直接*2
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
//创建一个指针来接收开辟的空间的地址
SLDataType* pf = NULL;
//使用realloc来开辟空间
pf = (SLDataType*)realloc(ps->arr, newcapacity*sizeof(SLDataType));
//检查是否开辟成功
if (pf==NULL)
{
perror("realloc");
//退出程序
exit(-1);
}
//把开辟的空间的地址赋值个arr指针
ps->arr = pf;
//同时把新空间容量的大小赋值给结构中用来记录容量的值
ps->capacity =newcapacity;
}
}
// 顺序表打印
void SeqListPrint(SeqList* ps)
{
//断言
assert(ps);
//通过循环打印
for (int i = 0; i < ps->size; i++)
{
printf("%d ", ps->arr[i]);
}
//换行
printf("\n");
}
// 顺序表销毁
void SeqListDestory(SeqList* ps)
{
//断言
assert(ps);
//释放空间
free(ps->arr);
//然后把指针置空
ps->arr = NULL;
//把有效数据个数和容量空间的大小都置为0
ps->capacity = 0;
ps->size = 0;
}
在尾插的时候要考虑两种情况:
// 顺序表尾插
void SeqListPushBack(SeqList* ps, SLDataType x)
{
//断言
assert(ps);
//对空间进行扩容
CheckCapacity(ps);
//把要插入的值插入顺序表
ps->arr[ps->size] = x;
//把记录有效数据个数的变量加1
ps->size++;
}
在主函数中的代码:
#include"List.h"
void List1()
{
SeqList sl;
SeqListInit(&sl);
SeqListPushBack(&sl, 1);
SeqListPushBack(&sl, 2);
SeqListPushBack(&sl, 3);
SeqListPushBack(&sl, 4);
SeqListPushBack(&sl, 5);
SeqListPrint(&sl);
SeqListDestory(&sl);
}
int main()
{
List1();
return 0;
}
// 顺序表尾删
void SeqListPopBack(SeqList* ps)
{
//断言指针是否为空
assert(ps);
//当只有size大于0的时候才能尾删
assert(ps->size > 0);
//尾删
ps->size--;
}
测试运行结果:
测试的代码
void List1()
{
SeqList sl;
SeqListInit(&sl);
SeqListPushBack(&sl, 1);
SeqListPushBack(&sl, 2);
SeqListPushBack(&sl, 3);
SeqListPushBack(&sl, 4);
SeqListPushBack(&sl, 5);
SeqListPrint(&sl);
SeqListPopBack(&sl);
SeqListPrint(&sl);
SeqListPopBack(&sl);
SeqListPrint(&sl);
SeqListPopBack(&sl);
SeqListPrint(&sl);
SeqListPopBack(&sl);
SeqListPrint(&sl);
SeqListPopBack(&sl);
SeqListPrint(&sl);
SeqListPopBack(&sl);
SeqListPrint(&sl);
SeqListDestory(&sl);
}
运行结果:
这就是断言起到的作用,当删除的数据太多的时候就会中止程序。
下面是正常删除的演示
测试代码:
void List1()
{
SeqList sl;
SeqListInit(&sl);
SeqListPushBack(&sl, 1);
SeqListPushBack(&sl, 2);
SeqListPushBack(&sl, 3);
SeqListPushBack(&sl, 4);
SeqListPushBack(&sl, 5);
SeqListPrint(&sl);
SeqListPopBack(&sl);
SeqListPrint(&sl);
SeqListPopBack(&sl);
SeqListPrint(&sl);
SeqListPopBack(&sl);
SeqListPrint(&sl);
SeqListDestory(&sl);
}
代码如下:
// 顺序表头插
void SeqListPushFront(SeqList* ps, SLDataType x)
{
//断言指针是否为空
assert(ps);
//扩容
CheckCapacity(ps);
//定义一个变量来接收顺序表中的有效个数
int i = ps->size;
//把数据向后移动空出头的位置
while (i)
{
ps->arr[i] = ps->arr[i- 1];
i--;
}
//给头的位置赋值
ps->arr[0] = x;
//然后有效数据个数加1
ps->size++;
}
测试代码和运行结果:
测试代码:
void List2()
{
SeqList sl;
SeqListInit(&sl);
SeqListPushBack(&sl, 1);
SeqListPushBack(&sl, 2);
SeqListPushBack(&sl, 3);
SeqListPushBack(&sl, 4);
SeqListPushBack(&sl, 5);
SeqListPrint(&sl);
SeqListPushFront(&sl, 0);
SeqListPrint(&sl);
SeqListDestory(&sl);
}
接口代码如下:
//顺序表头删
void SeqListPopFront(SeqList* ps)
{
//断言
assert(ps);
//控制size的值大于0
assert(ps->size > 0);
//定义一个变量来接收顺序表中的有效个数
int i = 1;
//把后面的数据向前移动
while (i<ps->size)
{
ps->arr[i - 1] = ps->arr[i];
i++;
}
//把有效数据减1
ps->size--;
}
测试代码和运行结果:
测试代码:
void List3()
{
SeqList sl;
SeqListInit(&sl);
SeqListPushBack(&sl, 1);
SeqListPushBack(&sl, 2);
SeqListPushBack(&sl, 3);
SeqListPushBack(&sl, 4);
SeqListPushBack(&sl, 5);
SeqListPrint(&sl);
SeqListPopFront(&sl);
SeqListPrint(&sl);
SeqListPopFront(&sl);
SeqListPrint(&sl);
SeqListDestory(&sl);
}
int SeqListFind(SeqList* ps, SLDataType x)
{
//断言
assert(ps);
//遍历数据
for (int i = 0; i < ps->size; i++)
{
//找到数据
if (ps->arr[i]==x)
{
//返回下标
return i;
}
}
//没有找到返回-1
return -1;
}
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* ps, int pos, SLDataType x)
{
assert(ps);
//扩容
CheckCapacity(ps);
assert(0 <= pos && pos <= ps->size);
int begin = ps->size;
//把pos之后的数据向后移动
while (begin>pos)
{
ps->arr[begin] = ps->arr[begin-1];
begin--;
}
ps->arr[pos] = x;
ps->size++;
}
测试代码和运行结果:
测试代码:
void List4()
{
SeqList sl;
SeqListInit(&sl);
SeqListPushBack(&sl, 1);
SeqListPushBack(&sl, 2);
SeqListPushBack(&sl, 3);
SeqListPushBack(&sl, 4);
SeqListPushBack(&sl, 5);
SeqListPrint(&sl);
printf("请输入插入的位置和数据:");
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
int pos = SeqListFind(&sl, a);
if (pos!=-1)
{
SeqListInsert(&sl, pos, b);
}
SeqListPrint(&sl);
SeqListDestory(&sl);
}
// 顺序表删除pos位置的值
void SeqListErase(SeqList* ps, int pos)
{
//断言
assert(ps);
//控制数据个数
assert(ps->size > 0);
assert(0 <= pos && ps->size > pos);
int begin = pos;
//把pos之后的数据向前移动
while (begin<ps->size)
{
ps->arr[begin] = ps->arr[begin + 1];
begin++;
}
ps->size--;
}
测试代码和运行结果:
测试代码:
void List5()
{
SeqList sl;
SeqListInit(&sl);
SeqListPushBack(&sl, 1);
SeqListPushBack(&sl, 2);
SeqListPushBack(&sl, 3);
SeqListPushBack(&sl, 4);
SeqListPushBack(&sl, 5);
SeqListPrint(&sl);
printf("请输入删除的数据:");
int a = 0;
scanf("%d", &a);
int pos = SeqListFind(&sl, a);
if (pos != -1)
{
SeqListErase(&sl, pos);
}
SeqListPrint(&sl);
SeqListDestory(&sl);
}
List.c文件代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include"List.h"
//顺序表的初始化
void SeqListInit(SeqList* ps)
{
//断言传过来的指针是否为空
assert(ps);
//首先把指向数组的指针置空
ps->arr = NULL;
//在把有效数据个数置空
ps->size = 0;
//给容量付个初始值
ps->capacity = 0;
}
// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList* ps)
{
//对指针进行断言
assert(ps);
//判断空间是否为空或者数据满了
if (ps->size==ps->capacity)
{
//定义一个变量来接收容量的值
//当容量的值为0的时候直接赋值为4,不为空的时候直接*2
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
//创建一个指针来接收开辟的空间的地址
SLDataType* pf = NULL;
//使用realloc来开辟空间
pf = (SLDataType*)realloc(ps->arr, newcapacity*sizeof(SLDataType));
//检查是否开辟成功
if (pf==NULL)
{
perror("realloc");
//退出程序
exit(-1);
}
//把开辟的空间的地址赋值个arr指针
ps->arr = pf;
//同时把新空间容量的大小赋值给结构中用来记录容量的值
ps->capacity =newcapacity;
}
}
// 顺序表打印
void SeqListPrint(SeqList* ps)
{
//断言
assert(ps);
//通过循环打印
for (int i = 0; i < ps->size; i++)
{
printf("%d ", ps->arr[i]);
}
//换行
printf("\n");
}
// 顺序表销毁
void SeqListDestory(SeqList* ps)
{
//断言
assert(ps);
//释放空间
free(ps->arr);
//然后把指针置空
ps->arr = NULL;
//把有效数据个数和容量空间的大小都置为0
ps->capacity = 0;
ps->size = 0;
}
// 顺序表尾插
void SeqListPushBack(SeqList* ps, SLDataType x)
{
//断言
assert(ps);
//对空间进行扩容
CheckCapacity(ps);
//把要插入的值插入顺序表
ps->arr[ps->size] = x;
//把记录有效数据个数的变量加1
ps->size++;
}
// 顺序表尾删
void SeqListPopBack(SeqList* ps)
{
//断言指针是否为空
assert(ps);
//当只有size大于0的时候才能尾删
assert(ps->size > 0);
//尾删
ps->size--;
}
// 顺序表头插
void SeqListPushFront(SeqList* ps, SLDataType x)
{
//断言指针是否为空
assert(ps);
//扩容
CheckCapacity(ps);
//定义一个变量来接收顺序表中的有效个数
int i = ps->size;
//把数据向后移动空出头的位置
while (i)
{
ps->arr[i] = ps->arr[i- 1];
i--;
}
//给头的位置赋值
ps->arr[0] = x;
//然后有效数据个数加1
ps->size++;
}
//顺序表头删
void SeqListPopFront(SeqList* ps)
{
//断言
assert(ps);
//控制size的值大于0
assert(ps->size > 0);
//定义一个变量来接收顺序表中的有效个数
int i = 1;
//把后面的数据向前移动
while (i<ps->size)
{
ps->arr[i - 1] = ps->arr[i];
i++;
}
//把有效数据减1
ps->size--;
}
// 顺序表查找
int SeqListFind(SeqList* ps, SLDataType x)
{
//断言
assert(ps);
//遍历数据
for (int i = 0; i < ps->size; i++)
{
//找到数据
if (ps->arr[i]==x)
{
//返回下标
return i;
}
}
//没有找到返回-1
return -1;
}
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* ps, int pos, SLDataType x)
{
assert(ps);
//扩容
CheckCapacity(ps);
assert(0 <= pos && pos <= ps->size);
int begin = ps->size;
//把pos之后的数据向后移动
while (begin>pos)
{
ps->arr[begin] = ps->arr[begin-1];
begin--;
}
ps->arr[pos] = x;
ps->size++;
}
// 顺序表删除pos位置的值
void SeqListErase(SeqList* ps, int pos)
{
//断言
assert(ps);
//控制数据个数
assert(ps->size > 0);
assert(0 <= pos && ps->size > pos);
int begin = pos;
//把pos之后的数据向前移动
while (begin<ps->size)
{
ps->arr[begin] = ps->arr[begin + 1];
begin++;
}
ps->size--;
}
List.h代码:
#pragma once
#include
#include
#include
#include
//静态顺序表
//#define n 10
//
//typedef int SLDataType;
//typedef struct SeqList
//{
// //定长数组
// SLDataType arr[n];
// //有效数据的个数
// int size;
//}SeqList;
//动态顺序表
typedef int SLDataType;
typedef struct SeqList
{
//指向动态开辟的数组
SLDataType* arr;
//有效数据的个数
int size;
//容量空间的大小
int capacity;
}SeqList;
//顺序表的初始化
void SeqListInit(SeqList* ps);
// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList* ps);
// 顺序表打印
void SeqListPrint(SeqList* ps);
// 顺序表销毁
void SeqListDestory(SeqList* ps);
// 顺序表尾插
void SeqListPushBack(SeqList* ps, SLDataType x);
// 顺序表尾删
void SeqListPopBack(SeqList* ps);
// 顺序表头插
void SeqListPushFront(SeqList* ps, SLDataType x);
//顺序表头删
void SeqListPopFront(SeqList* ps);
// 顺序表查找
int SeqListFind(SeqList* ps, SLDataType x);
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* ps, int pos, SLDataType x);
// 顺序表删除pos位置的值
void SeqListErase(SeqList* ps, int pos);
test.c文件代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include"List.h"
void List1()
{
SeqList sl;
SeqListInit(&sl);
SeqListPushBack(&sl, 1);
SeqListPushBack(&sl, 2);
SeqListPushBack(&sl, 3);
SeqListPushBack(&sl, 4);
SeqListPushBack(&sl, 5);
SeqListPrint(&sl);
SeqListPopBack(&sl);
SeqListPrint(&sl);
SeqListPopBack(&sl);
SeqListPrint(&sl);
SeqListPopBack(&sl);
SeqListPrint(&sl);
SeqListDestory(&sl);
}
void List2()
{
SeqList sl;
SeqListInit(&sl);
SeqListPushBack(&sl, 1);
SeqListPushBack(&sl, 2);
SeqListPushBack(&sl, 3);
SeqListPushBack(&sl, 4);
SeqListPushBack(&sl, 5);
SeqListPrint(&sl);
SeqListPushFront(&sl, 0);
SeqListPrint(&sl);
SeqListDestory(&sl);
}
void List3()
{
SeqList sl;
SeqListInit(&sl);
SeqListPushBack(&sl, 1);
SeqListPushBack(&sl, 2);
SeqListPushBack(&sl, 3);
SeqListPushBack(&sl, 4);
SeqListPushBack(&sl, 5);
SeqListPrint(&sl);
SeqListPopFront(&sl);
SeqListPrint(&sl);
SeqListPopFront(&sl);
SeqListPrint(&sl);
SeqListDestory(&sl);
}
void List4()
{
SeqList sl;
SeqListInit(&sl);
SeqListPushBack(&sl, 1);
SeqListPushBack(&sl, 2);
SeqListPushBack(&sl, 3);
SeqListPushBack(&sl, 4);
SeqListPushBack(&sl, 5);
SeqListPrint(&sl);
printf("请输入插入的位置和数据:");
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
int pos = SeqListFind(&sl, a);
if (pos!=-1)
{
SeqListInsert(&sl, pos, b);
}
SeqListPrint(&sl);
SeqListDestory(&sl);
}
void List5()
{
SeqList sl;
SeqListInit(&sl);
SeqListPushBack(&sl, 1);
SeqListPushBack(&sl, 2);
SeqListPushBack(&sl, 3);
SeqListPushBack(&sl, 4);
SeqListPushBack(&sl, 5);
SeqListPrint(&sl);
printf("请输入删除的数据:");
int a = 0;
scanf("%d", &a);
int pos = SeqListFind(&sl, a);
if (pos != -1)
{
SeqListErase(&sl, pos);
}
SeqListPrint(&sl);
SeqListDestory(&sl);
}
int main()
{
List5();
return 0;
}
代码如下:
int removeElement(int* nums, int numsSize, int val){
//定义两个变量
int src=0;
int dest=0;
//控制src的值不能越界
while(src<numsSize)
{
//要是不等于就直接赋值
if(nums[src]!=val)
{
nums[dest]=nums[src];
dest++;
src++;
}
else
{
src++;
}
}
return dest;
}
代码如下:
int removeDuplicates(int* nums, int numsSize){
int n=numsSize;
int dst=0;
int src=1;
while(src<n)
{
if(nums[dst]!=nums[src])
{
nums[dst+1]=nums[src];
dst++;
src++;
}
else
{
src++;
}
}
return dst+1;
}
以上就是我关于线性表中的顺序表的总结主要从顺序表的结构、顺序表的接口实现和力扣真题这3个方面进行总结,在线性表中不止有顺序表还有链表,下篇主要就是围绕顺序表来总结,希望这篇博客对大家有用。