文章目录
1.顺序表
1.1 概念及结构
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
顺序表一般可以分为:
- 静态顺序表:使用定长数组存储元素。
- 动态顺序表:使用动态开辟的数组存储。
1.2接口实现
静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。
1.2.1 头文件
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLDataType;
typedef struct seqlist
{
SLDataType* a;
int size;//元素个数
int capacity;//容量
}SL;
//顺序表打印
void SLPrint(SL* ps);
//顺序表初始化
void SLInit(SL* ps);
//顺序表销毁
void SLDestroy(SL* ps);
// 尾插尾删
void SLPushBack(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
//头插头删
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);
// 中间插入删除
// 在pos位置插入数据
void SLInsert(SL* ps, int pos, SLDataType x);
// 删除pos位置数据
void SLErase(SL* ps, int pos);
//查找元素
int SLFind(SL* ps, SLDataType x);
1.2.2函数实现部分
#define _CRT_SECURE_NO_WARNINGS 1
#include"seqlist.h"
void SLInit(SL* ps)
{
assert(ps);
ps->a = NULL;
ps->size = 0;
ps->capacity = 0;
}
//打印
void SLPrint(SL* ps)
{
assert(ps);
int i = 0;
for (i = 0; i < ps->size; i++)
{
printf("%d", ps->a[i]);
}
}
//摧毁顺序表
void SLDestroy(SL* ps)
{
assert(ps);
if (ps->a)
{
ps->a = NULL;
ps->size = 0;
ps->capacity = 0;
}
}
//检查扩容
void checkcapacity(SL*ps)
{
assert(ps);
if (ps->size == ps->capacity)
{
int newcapacity = (ps->capacity == 0 ? 4 : 2 * (ps->capacity));
SLDataType*p = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));//注意数据类型
if (p == NULL)
{
perror(realloc);
}
ps->a = p;
ps->capacity = newcapacity;
}
}
//尾插
void SLPushBack(SL* ps,SLDataType x)
{
assert(ps);
checkcapacity(ps);
ps->a[ps->size] = x;
ps->size++;
}
//尾删
void SLPopBack(SL* ps)
{
assert(ps);
assert(ps->size);
ps->size--;
}
//头插
void SLPushFront(SL* ps, SLDataType x)
{
assert(ps);
checkcapacity(ps);
int end = ps->size - 1;
while (end >= 0)
{
ps->a[end + 1] = ps->a[end];
end--;
}
ps->a[0] = x;
ps->size++;
}
//头删
void SLPopFront(SL* ps)
{
assert(ps);
assert(ps->size > 0);
int start = 1;
while (start < ps->size)
{
ps->a[start - 1] = ps->a[start];
start++;
}
ps->size--;
}
//任意位置插入
void SLInsert(SL* ps, int pos, SLDataType x)
{
assert(ps);
checkcapacity(ps);
int end = ps-> size - 1;
while (end >= pos)
{
ps->a[end + 1] = ps->a[end];
end--;
}
ps->a[pos] = x;
ps->size++;
}
//任意位置删除
void SLErase(SL* ps, int pos)
{
assert(ps);
assert(ps->size > 0);
int start =pos+1;
while (start < ps->size)
{
ps->a[start - 1] = ps->a[start];
start++;
}
ps->size--;
}
//查找
int SLFind(SL* ps, SLDataType x)
{
assert(ps);
int i = 0;
for (i = 0; i < ps->size; i++)
{
if (x == ps->a[i])
{
return i;
}
}
return -1;
}
1.2.3主函数部分
#define _CRT_SECURE_NO_WARNINGS 1
#include"seqlist.h"
void testseqlist()
{
SL s1;
SLInit(&s1);
SLPushBack(&s1, 1);
SLPushBack(&s1, 2);
SLPushBack(&s1, 3);
SLPushBack(&s1, 4);
SLPushBack(&s1, 5);
SLPushFront(&s1, 5);
SLPushBack(&s1, 5);
SLPopFront(&s1);
SLPopBack(&s1);
int pos = SLFind(&s1, 4);
printf("%d\n", pos);
SLInsert(&s1, 0, 2);
SLErase(&s1, 2);
SLPrint(&s1);
SLDestroy(&s1);
}
int main()
{
testseqlist();
return 0;
}
1.3数组相关面试题
1.3.1第一题
int removeElement(int* nums, int numsSize, int val){
int i=0;
int j=0;
for(i=0;i<numsSize;i++)
{
if(nums[i]!=val)
{
nums[j++]=nums[i];
}
}
return j;
}
1.3.2第二题
int removeDuplicates(int* nums, int numsSize)
{
int fast=0;//双指针来解决
int slow=0;
while(fast<numsSize&&slow<numsSize)
{
if(nums[fast]!=nums[slow])
{
nums[++slow]=nums[fast];
}
fast++;
}
return ++slow;
}
1.3.3第三题
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
int n1=m-1;//三指针解决
int n2=n-1;
int n3=m+n-1;
while(n1>=0&&n2>=0)
{
if(nums1[n1]>=nums2[n2])
{
nums1[n3--]=nums1[n1];
n1--;
}
else
{
nums1[n3--]=nums2[n2];
n2--;
}
}
while(n2>=0)
{
nums1[n3--]=nums2[n2--];
}
return nums1;
}
1.4 顺序表的问题及思考
问题:
- 中间/头部的插入删除,时间复杂度为O(N)
- 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
- 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间