一、线性表
线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使 用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的, 线性表在物理上存储时,通常以数组和链式结构的形式存储。
二、顺序表
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存 储。在数组上完成数据的增删查改。
(1)静态顺序表:使用定长数组存储元素。
(2)动态顺序表:使用动态开辟的数组存储。
注意:动态顺序表在扩容的时候,存在异地扩容还是本地扩容。当本地空间足够的时候,就能够本地扩容,当本地空间不够的时候,则会存在异地扩容。具体的操作看操作系统,我们只负责在空间不够时,进行扩容(在动态顺序表的时候)。
顺序表的模拟实现:
queue的头文件部分:
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int SLDatatype;
typedef struct SeqList
{
SLDatatype* a;
int size; // 有效数据
int capacity; //已开辟的空间大小
}SL;
void SLInit(SL* p); //初始化
void SLDestroy(SL* p); //销毁顺序表
void SLPrint(SL* p); //打印表中的数据
void SLCheckCapacity(SL* p); //检查空间是否够
//尾插尾删
void SLPushBack(SL* p, SLDatatype x);
void SLPopBack(SL* p);
//头插头删
void SLPushFront(SL* p, SLDatatype x);
void SLPopFront(SL* p);
//任意位置的插入删除
void SLInsert(SL* p, SLDatatype x, int pos);
void SLErase(SL* p, int pos);
//找表中的某一个数据
int SLFind(SL* p, SLDatatype x);
int SLFind_over(SL* p, SLDatatype x, int begin);//从指定的位置开始寻找
函数实现部分:
#include"SeqList.h"
void SLInit(SL* p) //初始化
//初始化的时候,可以不同的方法,例如可以先进行开辟一定的空间,也可以等插入数据的时候在进行开辟空间
{
assert(p);//检查p是否为NULL,防止对NULL的调用
p->a = NULL;
p->size = 0;
p->capacity = 0;
}
void SLDestroy(SL* p) //销毁顺序表
{
assert(p);
if (p->a != NULL)
{
free(p->a);
p->size = p->capacity = 0;
}
}
void SLPrint(SL* p) //打印表中的数据
{
assert(p);
for (int i = 0;i < p->size;i++)
{
printf("%d ", p->a[i]);
}
printf("\n");
}
void SLCheckCapacity(SL* p) //检查空间是否够
{
assert(p);
if (p->size == p->capacity)
{
int newCapacity = p->capacity == 0 ? 4 : (p->capacity) * 2;
SLDatatype* tmp = (SLDatatype*)realloc(p->a, newCapacity * sizeof(SLDatatype));
if (tmp == NULL)//malloc的检查机制,防止malloc没有开辟成功的时候,给我报错误点在malloc没有开辟成功
{
perror("relloc fail");
}
p->a = tmp;
p->capacity = newCapacity;
}
}
void SLPushBack(SL* p, SLDatatype x)
{
assert(p);
SLCheckCapacity(p);//检查空间是否够,是否需要扩容
p->a[p->size] = x;
p->size++;
}
void SLPopBack(SL* p)
{
assert(p);
assert(p->size > 0);
//有数据才能进行删除,当没有数据的时候,再进行删除就会纯真野指针问题
p->size--;
}
void SLPushFront(SL* p, SLDatatype x)
{
assert(p);
SLCheckCapacity(p);
int end = p->size;
while (end > 0)//因为在头部插入数据,需要移动数据
{
p->a[end] = p->a[end - 1];
end--;
}
p->a[end] = x;
p->size++;
}
void SLPopFront(SL* p)
{
assert(p);
assert(p->size > 0);
int begin = 0;
while (begin < p->size - 1)//同理需要移动数据
{
p->a[begin] = p->a[begin + 1];
begin++;
}
p->size--;
}
void SLInsert(SL* p, SLDatatype x, int pos)
{
assert(p);
assert(pos >= 0);
assert(pos <= p->size);
SLCheckCapacity(p);
for (int i = p->size;i > pos;i--)
{
p->a[i] = p->a[i - 1];
}
p->a[pos] = x;
p->size++;
}
void SLErase(SL* p, int pos)
{
assert(p);
int tmp = pos;
while (tmp < p->size - 1)
{
p->a[tmp] = p->a[tmp + 1];
tmp++;
}
p->size--;
}
int SLFind(SL* p, SLDatatype x)
{
assert(p);
for (int i = 0;i < p->size;i++)
{
if (p->a[i] == x)
return i;
}
return -1;
}
int SLFind_over(SL* p, SLDatatype x, int begin)
{
assert(p);
for (int i = begin;i < p->size;i++)
{
if (p->a[i] == x)
{
return i;
}
}
return -1;
}