目录
1.概念及结构
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。 数据必须从第一个位置开始,连续存储的
顺序表一般可以分为:
1.静态顺序表:使用定长数组存储元素。
2.动态顺序表:使用动态开辟的数组存储。
2.具体实现
Seqlish.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define N 200
typedef int SLDataType;
//静态顺序表 -- N太小,可能不够用,N太大,可能浪费空间
typedef struct SeqList
{
SLDataType* a; //指向动态数组指针
int size; //数据个数
int capacity; //容量-空间大小
}SL;
void SLPrint(SL* ps);
void SLPrint(SL* ps);
//增删查改
//void SeqListInit(SL* s)
void SLInit(SL* ps);
void SLDestory(SL* ps);
void SLCheckCapacity(SL* ps);
//头插/头删/尾插/尾删 -- STL
//O(1)
void SLPushBack(SL* ps, SLDataType x);
void SLPopback(SL* ps);
//O(N)
void SLPushFront(SL* ps, SLDataType X);
void SLPopFront(SL* ps);
//任意位置插入删除
void SLInsert(SL* ps,int pos, SLDataType x);
void SLErase(SL* ps, int pos);
//查找和修改
int SLFind(SL* ps, SLDataType x);
int SLModify(SL* ps, SLDataType x);
Test.c
#include "Seqlist.h"
void TestSeqList1()
{
SL sl;
SLInit(&sl);
SLPushBack(&sl, 1);
SLPushBack(&sl, 2);
SLPushBack(&sl, 3);
SLPushBack(&sl, 4);
SLPrint(&sl);
SLPushBack(&sl, 5);
SLPrint(&sl);
SLInsert(&sl,3,40);
SLPrint(&sl);
SLPopFront(&sl);
SLErase(&sl, 3);
SLDestory(&sl);
}
int main()
{
TestSeqList1();
//越界是不一定报错的
//系统对越界的检查,设岗抽查
//int a[10];
//a[0] = 0;
a[10] = 1;
a[11] = 1;
//a[12] = 1;
//a[15] = 1;
return 0;
}
初始化SLInit
void SLInit(SL* ps)
{
assert(ps != NULL);
ps->a = NULL;
ps->size = ps->capacity = 0;
}
1.判断ps是否为空指针
2.将结构体a置为NULL
3.将size和capacity置为0
尾插SLPushBack
void SLPushBack(SL* ps, SLDataType x)
{
assert(ps != NULL);
SLCheckCapacity(ps);
ps->a[ps->size] = x;
ps->size++;
}
1.所有需要对顺序表修改的函数首先CheckCapacity
2.将表中最后一个元素赋值后++size
打印SLPrint
void SLPrint(SL* ps)
{
assert(ps != NULL);
for (int i = 0; i < ps->size; ++i)
{
printf("%d ", ps->a[i]);
}
printf("\n");
}
遍历表中所有元素并打印
头插SLPushFront
void SLPushFront(SL* ps, SLDataType x)
{
assert(ps != NULL);
SLCheckCapacity(ps);
//挪动数据
int end = ps->size - 1;
while (end >= 0)
{
ps->a[end + 1] = ps->a[end];
--end;
}
ps->a[0] = x;
ps->size++;
}
先把表中所有元素往后挪一个位置,再在头部插入一个数
检查容量CheckCapacity
void SLCheckCapacity(SL* ps)
{
assert(ps != NULL);
//检查容量空间,满了扩容
if (ps->size == ps->capacity)
{
int NewCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
SLDataType* tmp = realloc(ps->a, sizeof(SLDataType) * NewCapacity);
if (tmp == NULL)
{
printf("realloc fail\n");
//exit(-1);
return;
}
ps->a = tmp;
ps->capacity = NewCapacity;
}
}
1.当size=capacity时需要增容
2.当表内没有元素即size为零时,初始值为4,否则double给到NewCapacity
3.realloc开辟空间后不要马上给指针a,而是存储在tmp中,因为realloc后可能开辟失败
尾删SLPopBack
void SLPopBack(SL* ps)
{
//ps->a[ps->size - 1] = 0;
//温柔检查
//if (ps->size == 0)
//{
// printf("SeqList is empty\n");
// return;
//}
//暴力检查
assert(ps != NULL);
assert(ps->size > 0);
ps->size--;
}
size--等价于删除这个元素,尽管他还在表中,但已经失去对他的访问权
删表SLDestory
void SLDestory(SL* ps)
{
assert(ps != NULL);
if (ps->a)
{
free(ps->a);
ps->a = NULL;
ps->capacity = ps->size = 0;
}
}
1.将之前为指针a开辟的空间释放掉,并置为NULL
2.将capacity和size重新置为零
头删SLPopFront
void SLPopFront(SL* ps)
{
assert(ps != NULL);
assert(ps->size > 0);
int begin = 1;
while (begin < ps->size)
{
ps->a[begin - 1] = ps->a[begin];
++begin;
}
ps->size--;
}
从第二个元素开始,依次把前一个元素覆盖
任意插SLInsert
void SLInsert(SL* ps, int pos, SLDataType x)
{
assert(ps);
assert(ps >= 0 && pos <= ps->size);
SLCheckCapacity(ps);
//挪用数据
int end = ps->size - 1;
while (end >= pos)
{
ps->a[end + 1] = ps->a[end];
--end;
}
ps->a[pos] = x;
ps->size++;
}
1.将需要插入的位置后的第end-pos个元素依次从后往前挪
2.将元素插入pos位置
3.assert(ps)等价于assert(ps!=NULL)
任意删SLErase
void SLErase(SL* ps, int pos)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);
int begin = pos;
while (begin < ps->size - 1)
{
ps->a[begin] = ps->a[begin + 1];
++begin;
}
ps->size--;
}
从需要删的元素开始用后一个覆盖前一个
查找SLFind
int SLFind(SL* ps, SLDataType x)
{
int pos = 0;
for (int i = 0; i < ps->size; ++i)
{
if (ps->a[i] == x)
{
pos = i;
return pos;
}
else
return -1;
}
}
遍历表中所有元素,找到返回当前下标,否则return -1
调整SLModify
int SLModify(SL* ps, int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);
if(pos == SLFind(ps,pos))
ps->a[pos] = x;
}
借助前面写的查找SLFind函数,找到后返回下标然后进行修改