顺序表就是数组,但是数据必须从第一个位置开始连续存储
顺序表是用一段 物理地址连续 的存储单元依次存储数据元素的线性结构,一般情况下采用数组存 储,在数组上完成数据的增删查改 1. 静态顺序表使用定长数组存储元素
#define N 200
typedef int SLDataType;
struct SeqList
{
SLDataType a[N];//定义一个数组
int size;//数据个数
};
N太小可能不够用,N太大可能浪费空间
2. 动态顺序表 使用动态开辟的数组存储#define SEQ_INIT_SIZE 10//初始容量
#define SEQ_INC_SIZE 2//每次增容的倍数
typedef struct SeqList
{
SLDataType* a;//指向动态数组指针
int sz;//数据个数
int capacity;//容量 -空间大小
}SeqList;
空间不够则增容
2.2 接口实现#include
#include
#include
#include
#define SEQ_INIT_SIZE 10//初始容量
#define SEQ_INC_SIZE 2//每次增容的倍数
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define NULLPTR -3
typedef int status;//状态
typedef int SLDataType;//元素类型
1.顺序表初始化
void SeqListInit(SeqList* ps)
{
assert(ps != NULL);
ps->capacity = SEQ_INIT_SIZE;
ps->sz = 0;
ps->a = (SLDataType*)malloc(sizeof(SLDataType) * ps->capacity);
if (ps->a == NULL)exit(-1);
}
2.打印顺序表
void SeqListPrint(const SeqList* ps)
{
assert(ps != NULL);
for (int i = 0; i < ps->sz; i++)
{
printf("%d ", ps->a[i]);
}
printf("\n");
}
3.查找某元素返回下标
int SeqListFind(const SeqList* ps, SLDataType x)
{
assert(ps != NULL);
for (int i = 0; i < ps->sz; i++)
{
if (ps->a[i] == x)return i;
}
return -1;
}
4.顺序表增容(malloc)
bool IncCapacity(SeqList* ps)
{
assert(ps != NULL);
int newcapacity = ps->capacity * SEQ_INC_SIZE;
SLDataType* newdata = (SLDataType*)malloc(sizeof(SLDataType) * newcapacity);
if (newdata == NULL)return false;
for (int i = 0; i < ps->capacity; i++)
{
newdata[i] = ps->a[i];
}
free(ps->a);
ps->a = newdata;
ps->capacity = newcapacity;
return true;
}
5.顺序表增容(realloc)
bool IncCapacity(SeqList* ps)
{
assert(ps != NULL);
int newcapacity = ps->capacity * SEQ_INC_SIZE;
SLDataType* newdata = (SLDataType*)realloc(ps->a,sizeof(SLDataType) * newcapacity);
if (newdata == NULL)return false;
ps->a = newdata;
ps->capacity = newcapacity;
return true;
}
6.顺序表判满
bool IsFull(const SeqList* ps)
{
assert(ps != NULL);
return ps->sz == ps->capacity;
}
7.在pos位置插入x
status SeqListInsert(SeqList* ps, int pos, SLDataType x)
{
assert(ps != NULL);
if (pos<0 || pos>ps->sz)return INFEASIBLE;
if (IsFull(ps) && !IncCapacity(ps))return OVERFLOW;//没满和满了但增容成功都不return,满了但增容失败return
for (int i = ps->sz - 1; i >= pos; i--)
{
ps->a[i + 1] = ps->a[i];
}
ps->a[pos] = x;
ps->sz++;
return OK;
}
8.顺序表尾插
void SeqListPushBack(SeqList* ps, SLDataType x)
{
assert(ps != NULL);
SeqListInsert(ps, ps->sz, x);
}
9.顺序表头插
void SeqListPushFront(SeqList* ps, SLDataType x)
{
assert(ps != NULL);
SeqListInsert(ps, 0, x);
}
10.删除pos位置元素
status SeqListErase(SeqList* ps,int pos)
{
assert(ps != NULL);
if (pos<0 || ps>ps->sz - 1)return INFEASIBLE;
for (int i = pos; i < ps->sz-1; i++)
{
ps->a[i] = ps->a[i + 1];
}
ps->sz--;
return OK;
}
11.顺序表尾删
void SeqListPopBack(SeqList* ps)
{
assert(ps != NULL);
SeqListErase(ps,ps->sz-1);
}
12.顺序表头删
void SeqListPopFront(SeqList* ps)
{
assert(ps != NULL);
SeqListErase(ps,0);
}
13.顺序表清空
void SeqListClear(SeqList* ps)
{
assert(ps != NULL);
ps->sz = 0;
}
14.顺序表销毁
void SeqListDestory(SeqList* ps)
{
assert(ps != NULL);
ps->capacity = 0;
ps->sz = 0;
free(ps->a);
}
2.3 数组相关面试题
实例1
原地移除数组中所有的元素
val
,要求时间复杂度为
O(N)
,空间复杂度为
O(1)
int removeElement(int* nums, int numsSize, int val){
int j=-1;
for(int i=0;i
2个指针,把不删的向前移把要删的覆盖了,1个指针始终指着不删的下标,另一个指针游历判断删不删,最后指着不删的下标的指针+1是剩下元素的个数
实例2 删除排序数组中的重复项int removeDuplicates(int* nums, int numsSize){
int i=0,j=0;
while(j!=numsSize)
{
if(nums[i]==nums[j])
{
j++;
}
else
{
i++;
nums[i]=nums[j];
j++;
}
}
return i+1;
}
实例3
合并两个有序数组
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
int i=m-1;
int j=n-1;
int k=m+n-1;
while(i>=0&&j>=0)
{
nums1[k--]=nums1[i]>=nums2[j]?nums1[i--]:nums2[j--];
}
while(j>=0)
{
nums1[k--]=nums2[j--];
}
}
2.4 顺序表的问题
问题:
1. 中间/头部的插入删除,效率低,时间复杂度为O(N)
2. 增容需要申请新空间,拷贝数据,释放旧空间会有不小的消耗 3. 增容一般是呈2倍的增长,势必会有一定的空间浪费,例如当前容量为100,满了以后增容到 200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间 改善方案:1.按申请释放空间
2.头部或中间插入删除不需要挪动数据
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)