1.线性表
线性表是n个具有相同特性的数据元素的有限序列。常见的线性表:顺序表、链表、栈、队列、字符串…
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。
2.顺序表
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
顺序表一般可以分为:
- 静态顺序表:使用定长数组存储。
- 动态顺序表:使用动态开辟的数组存储
//动态顺序表
typedef struct seqList
{
SLDataType* _data;//数组指针
int _size;//有效元素的个数
int _capacity;//数组的空间
}seqList;
数据在另外一个空间存放,通过指针找到。
sizeof(seqList):12byte
空间已满:扩容
1.申请更大的空间
2.拷贝原有数据
3.释放原有的空间
4.更新容量
建立在堆上的,要自己free -----malloc
栈上的不需要
seqListDestory():销毁的是数据的空间
free():销毁的是动态开辟的变量的空间
顺序表的特点
1.空间连续
2.支持随机访问
3.尾插,尾删:O(1)
4.空间利用率高,不容易造成内存碎片
5.其它位置(除了尾部)插入删除:O(n)
6.增容的代价比较大
适合:访问,存储
顺序表接口的实现
#define N 100
typedef int SLDataType;
//顺序表:数组,数组相关信息:有效元素个数,数组的容量
//静态顺序表
struct seqList2
{
SLDataType _data[N];
int _size;
};
//动态顺序表
typedef struct seqList
{
SLDataType* _data;//数组指针
int _size;//有效元素的个数
int _capacity;//数组的空间
}seqList;
void initseqList(seqList* s1);//要修改变量内容,传值是拷贝
//操作 :增删查改
//尾插:给顺序表最后一个有效数据的末尾插入新的数据
void seqListPushBack(seqList* s1, SLDataType val);
void seqListcheckCapacity(seqList* s1);
SLDataType seqListAt(seqList* s1, int pos);
void seqListpopBack(seqList* s1);//尾删
void seqListPrint(seqList* s1);
int seqListEmpty(seqList* s1);
int seqListSize(seqList* s1);
void seqListPushFront(seqList* s1, SLDataType val);//头插
void seqListPopFront(seqList* s1);//头删
void seqListInsert(seqList* s1, int pos, SLDataType val);//任意位置插入
void seqListErase(seqList* s1, int pos);//任意位置删除
int seqListFind(seqList* s1, SLDataType val);
void seqListDestroy(seqList* s1);
代码实现:
#include "seqList.h"
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//初始化一个空的顺序表
void initseqList(seqList* s1)
{
if (s1 == NULL)
return;
s1->_data = NULL;
s1->_size = 0;
s1->_capacity = 0;
}
void seqListcheckCapacity(seqList* s1)
{
if (s1->_size == s1->_capacity)
{
//空间已满,扩容
//1.开新的空间
int newCapacity = s1->_capacity == 0 ? 1 : 2 * s1->_capacity;
SLDataType* tmp = (SLDataType*)malloc(newCapacity*sizeof(SLDataType));
//2.拷贝原有数据
memcpy(tmp, s1->_data, sizeof(SLDataType)*s1->_size);//按字节拷贝
//3.释放原有空间
free(s1->_data);
s1->_data = tmp;
// s1->_data = (SLDataType*)realloc(s1->_data, newCapacity*sizeof(SLDataType));
//4.更新容量
s1->_capacity = newCapacity;
}
}
void seqListPushBack(seqList* s1, SLDataType val)//尾插 :时间复杂度:O(1)
{
seqListcheckCapacity(s1);//检查容量
//尾插
s1->_data[s1->_size] = val;
s1->_size++;
}
void seqListpopBack(seqList* s1)
{
if (s1 == NULL)
return;
if (s1->_size > 0)//有数据才可以删除
s1->_size--;//假删除
}
void seqListPrint(seqList* s1)
{
if (s1 == NULL)
return;
for (int i = 0; i < s1->_size; ++i)
{
printf("%d ", s1->_data[i]);
}
printf("\n");
}
SLDataType seqListAt(seqList* s1, int pos)
{
return s1->_data[pos];
}
int seqListEmpty(seqList* s1)//判断是否为空
{
if (s1 == NULL || s1->_size == 0)
return 0;
else
return 1;
}
int seqListSize(seqList* s1)
{
if (s1 == NULL || s1->_size == 0)//s1==NULL判断必须在前,不然做解引用可能会出现问题
return 0;//程序直接挂掉
else
return s1->_size;
}
//头插:移动元素
//移动元素的方向:从后向前移动(防止数据被覆盖)
void seqListPushFront(seqList* s1, SLDataType val)
{
if (s1 = NULL)
return;
seqListcheckCapacity(s1);
int end = s1->_size;
while (end > 0)
{
s1->_data[end] = s1->_data[end - 1];//第零个元素放到第一个元素的位置
}
//插入
s1->_data[0] = val;
s1->_size++;
}
void seqListPopFront(seqList* s1)//头删
{
if (s1 == NULL || s1->_size == 0)
return;
//从前向后移动元素
int start = 1;
while (start < s1->_size)
{
s1->_data[start - 1] = s1->_data[start];//把第一个元素放到第零个元素的位置
start++;
}
//更新size
s1->_size--;
}
void seqListInsert(seqList* s1, int pos, SLDataType val)
{
//从pos位置开始移动元素:从后向前
//从pos位置插入新的元素
if (s1 = NULL)
return;
if (pos >= 0 && pos <= s1->_size)
{
seqListcheckCapacity(s1);
//移动元素:[pos,size)
int end = s1->_size;
while (end>pos)//pos位置要空出来,不能赋值
{
s1->_data[end] = s1->_data[end - 1];
--end;
}
s1->_data[pos] = val;
s1->_size++;
}
}
void seqListErase(seqList* s1, int pos)
{
//任意位置删除:pos 0<=pos<size
//移动元素:(pos,size) 从前向后移动
if (s1 == NULL || s1->_size == 0)
return;
if (0 <= pos&&pos < s1->_size)
{
int start = pos + 1;
while (start < s1->_size)
{
s1->_data[start - 1] = s1->_data[start];
++start;
}
--s1->_size;
}
}
int seqListFind(seqList* s1, SLDataType val)
{
if (s1 = NULL)
return 0;
for (int i = 0; i < s1->_size; ++i)
{
if (s1->_data[i] == val)
return i;
}
return 0;
}
void seqListDestroy(seqList* s1)
{
if (s1 != NULL&&s1->_data != NULL)
{
free(s1->_data);
s1->_data = NULL;
}
//销毁的是数据的空间
}
//free:销毁的是动态开辟的变量的空间
void test()
{
seqList s1;
initseqList(&s1);
}
int main()
{
test();
return 0;
}