线性表
线性表(linear list)是n个具有相同特性的数据元素的有限序列,线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串。
线性表在逻辑上是线性结构,也就是说是连续的一条直线。但物理结构上并不一定是连续的,线性表在物理存储时,通常以数组和链式结构的形式存储。
强调文本 强调文本
逻辑结构:想象出来的
物理结构:内存中如何存
顺序表
顺序表是一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。数组上完成数据的怎删改查。
顺序表可分为:
- 静态顺序表:使用定长数组存储(固定大小)
下面展示一些内联代码片
。
//顺序表的静态存储
#typedef N 100
#typedef int SLDataType
#typedef struct SeqList
{
SLDataType arr[N];//定长数组
int size;//有效数据的个数
}SL;
- 动态顺序表:使用动态开辟的数组存储
创建一个顺序表
//创建顺序表
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* arr;
int size;//有效数据个数
int capacity;//申请空间个数
}SL;
初始化
//顺序表初始化
void SLInit(SL* ps)
{
assert(ps);//检测空指针
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
*销毁
//销毁
void SLDestroy(SL* ps)
{
assert(ps);
free(ps->arr);//对动态分配的内存进行释放
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
*打印
//打印
void SLPrint(SL* ps)
{
for (int i = 0; i < ps->size; ++i)
printf("%d", ps->arr[i]);
printf("\n");
}
*扩容
//扩容
void SLCheckCapacity(SL* ps)
{
if(ps->size=ps->capacity)
{
int newcapacity=ps->capacity==0?4:2*(ps->capacity);
SLDataType* p=(SLDataType*)realloc(ps->arr,newcapacity*sizeof(SLDataType));
}
if(p==NULL)
{
perror("realloc fail!");
exit(1);
}
ps->arr=p;
ps->capacity=newcapacity;
}
*尾插
//尾插
void SLPushBack(SL* ps,SLDataType x)
{
assert(ps);
SLCheckCapacity(ps);
ps->arr[ps->size++] = x;
}
首插
//首插
void SLPushFront(SL* ps, SLDataType x)
{
assert(ps);
SLCheckCapacity(ps);
for (int i = ps->size; i > 0; --i)
ps->arr[i] = ps->arr[i - 1];
ps->arr[0] = x;
ps->size++;
}
指定位置插入
//指定位置插入
void SLInsert(SL* ps, SLDataType x, int pos)
{
assert(ps);
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 SLPopBack(SL* ps)
{
assert(ps);
ps->size--;
}
头删
//头删
void SLPopFront(SL* ps)
{
assert(ps);
for (int i = 1; i < ps->size; ++i)
ps->arr[i - 1] = ps->arr[i];
ps->size--;
}
指定位置删除
//指定位置删除
void SLErase(SL* ps, int pos)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);
for (int i = pos + 1; i < ps->size; ++i)
ps->arr[i - 1] = ps->arr[i];
ps->size--;
}
perror()是C语言标准库<stdio.h>中提供的函数,用于打印与最近的错误代码相关的错误信息。
exit函数是C标准库中的函数,其原型定义在stdlib.h头文件中。exit函数的作用是终止当前的程序执行,并返回一个指定的退出码给操作系统。
exit(0):正常运行并退出程序;
exit(1):非正常运行导致退出程序;
SeqList.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* arr;
int size;
int capacity;
}SL;
//顺序表初始化
void SLInit(SL* ps);
//销毁
void SLDestroy(SL* ps);
//打印
void SLPrint(SL* ps);
//扩容
void SLCheckCapacity(SL* ps);
//尾插
void SLPushBack(SL* ps, SLDataType x);
//首插
void SLPushFront(SL* ps, SLDataType x);
//指定位置插入
void SLInsert(SL* ps, SLDataType x, int pos);
//尾删
void SLPopBack(SL* ps);
//头删
void SLPopFront(SL* ps);
//指定位置删除
void SLErase(SL* ps, int pos);
#pragma once 用于防止头文件多次包含预处理指令。它的作用是确保同一个头文件在同一个编译器单元中只被包含一次,以避免重复定义错误和提高编译效率
SeqList.c
#include "SeqList.h"
//顺序表初始化
void SLInit(SL* ps)
{
assert(ps);
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
//销毁
void SLDestroy(SL* ps)
{
assert(ps);
free(ps->arr);
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
//打印
void SLPrint(SL* ps)
{
for (int i = 0; i < ps->size; ++i)
printf("%d", ps->arr[i]);
printf("\n");
}
//扩容
void SLCheckCapacity(SL* ps)
{
if (ps->size == ps->capacity)
{
int newcapacity = ps->capacity == 0 ? 4 : 2 * (ps->capacity);
SLDataType* p = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));
if (p == NULL)
{
perror("realloc fail!");
exit(1);
}
ps->arr = p;
ps->capacity = newcapacity;
}
}
//尾插
void SLPushBack(SL* ps,SLDataType x)
{
assert(ps);
SLCheckCapacity(ps);
ps->arr[ps->size++] = x;
}
//首插
void SLPushFront(SL* ps, SLDataType x)
{
assert(ps);
SLCheckCapacity(ps);
for (int i = ps->size; i > 0; --i)
ps->arr[i] = ps->arr[i - 1];
ps->arr[0] = x;
ps->size++;
}
//指定位置插入
void SLInsert(SL* ps, SLDataType x, int pos)
{
assert(ps);
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 SLPopBack(SL* ps)
{
assert(ps);
ps->size--;
}
//头删
void SLPopFront(SL* ps)
{
assert(ps);
for (int i = 1; i < ps->size; ++i)
ps->arr[i - 1] = ps->arr[i];
ps->size--;
}
//指定位置删除
void SLErase(SL* ps, int pos)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);
for (int i = pos + 1; i < ps->size; ++i)
ps->arr[i - 1] = ps->arr[i];
ps->size--;
}
test.c
#include "SeqList.h"
int main()
{
//尾插测试
SL arr;
SLInit(&arr);
SLPushBack(&arr, 1);
SLPushBack(&arr, 2);
SLPushBack(&arr, 3);
SLPushBack(&arr, 4);
SLPushBack(&arr, 5);
SLPushBack(&arr, 6);
SLPrint(&arr);
//首插测试
SLPushFront(&arr, 8);
SLPushFront(&arr, 7);
SLPushFront(&arr, 6);
SLPrint(&arr);
//指定位置插入测试
SLInsert(&arr, 0, 3);
SLInsert(&arr, 0, 5);
SLInsert(&arr, 0, 0);
SLPrint(&arr);
//尾删测试
SLPopBack(&arr);
SLPopBack(&arr);
SLPopBack(&arr);
SLPrint(&arr);
//头删测试
SLPopFront(&arr);
SLPopFront(&arr);
SLPopFront(&arr);
SLPrint(&arr);
//指定位置删除测试
SLErase(&arr,3);
SLErase(&arr, 3);
SLErase(&arr, 3);
SLPrint(&arr);
}
顺序表特点:
1.可动态增长的数组
2.数据在数组中存储时必须是连续的
缺点
1.中间或者头部的插入删除很慢,需要挪动数据。时间复杂度是O(N)
2.空间不够是,增容会有一定消耗和空间浪费。
优点
1.随机访问。(排序)
2.缓存命中率比较高。