目录
3、TestSeqList3(测试查找,指定位置增加和删除)
一、头文件
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
二、类型定义
typedef int SLDataType;//重定义一下数据类型,要修改时只需要将int改成char,double等等
//动态顺序表
typedef struct SeqList
{
SLDataType* a;
int size;//表示数组中存储了多少个有效数据,必须连着存
int capacity;//数组实际能存数据的空间容量是多大,指的是个数
}SL;
三、函数接口
//接口函数
void SeqListInit(SL* ps);//初始化
void SeqListPrint(SL* ps);//打印
void SeqListDestory(SL* ps);//销毁
void SeqListCheckCapacity(SL* ps);//检测容量
void SeqListPushBack(SL* ps, SLDataType x);//在尾部插入数据
void SeqListPopBack(SL* ps);//删除尾部数据
void SeqListPushFront(SL* ps, SLDataType x);//在头部插入数据
void SeqListPopFront(SL* ps);//删除头部数据
int SeqListFind(SL* ps, SLDataType x);//查找指定数据
void SeqListInsert(SL* ps, int pos, SLDataType x);//在指定的位置插入数据
void SeqListErase(SL* ps, int pos);//在指定的位置删除数据
四、函数功能
1、顺序表初始化
//初始化
void SeqListInit(SL* ps)
{
ps->a = NULL;
ps->size = 0;
ps->capacity = 0;
}
2、顺序表打印
//打印
void SeqListPrint(SL* ps)
{
int i = 0;
for (i = 0; i < ps->size; i++)
{
printf("%d ", ps->a[i]);
}
printf("\n");
}
3、顺序表销毁
//销毁
void SeqListDestory(SL* ps)
{
free(ps->a);
ps->a = NULL;
ps->size = 0;
ps->capacity = 0;
}
4、检测容量
//检测容量
void SeqListCheckCapacity(SL* ps)
{
//如果没有空间或者空间不足,就扩容
if (ps->size == ps->capacity)
{
//此时有两种情况,第一种是还没有空间,第二种是已经满了
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
//判断空间是否为0,如果为0,则开辟4个空间,如果不为0,则开辟当前空间的二倍的空间
SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));
//void* realloc(void* ptr,size_t size);
//realloc函数有一个特点,如果要增加的原数组空间大小为0,则功能类似于malloc函数,进行开辟
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);//exit直接退出程序,return只是退出这个函数
}
ps->a = tmp;
ps->capacity = newcapacity;
}
}
5、指定位置插入数据
//在指定的位置插入数据
void SeqListInsert(SL* ps, int pos, SLDataType x)
{
//插入的位置要和之前的数据连续
//第一种
/*if (pos > ps->size || pos < 0)
{
printf("pos invalid\n");
return;
}*/
//第二种
assert(pos >= 0 && pos <= ps->size);
//挪动数据
SeqListCheckCapacity(ps);//检查一下容量
int end = ps->size - 1;
while (end >= pos)
{
ps->a[end + 1] = ps->a[end];
--end;
}
ps->a[pos] = x;
ps->size++;
}
6、指定位置删除数据
//在指定的位置删除数据
void SeqListErase(SL* ps, int pos)
{
assert(pos >= 0 && pos < ps->size);
int begin = pos + 1;
while (begin < ps->size)
{
ps->a[begin - 1] = ps->a[begin];
++begin;
}
ps->size--;
}
7、尾部插入
//尾插
void SeqListPushBack(SL* ps, SLDataType x)
{
SeqListInsert(ps, ps->size, x);//调用一下任意插入函数,将参数改为ps->size即可实现尾插
}
8、尾部删除
//尾删
void SeqListPopBack(SL* ps)
{
第一种
///*if (ps->size > 0)
//{
// ps->size--;
//}*/
第二种
//assert(ps->size > 0);
//ps->size--;
SeqListErase(ps, ps->size-1);//直接调用任意位置删除函数,把参数改为ps->size-1,即可实现尾删
}
9、头部插入
//头插
void SeqListPushFront(SL* ps, SLDataType x)
{
//SeqListCheckCapacity(ps);//检查下容量
挪动数据,把后面的往后移,再把数据插入到第一个位置
//int end = ps->size - 1;
//while (end >= 0)
//{
// ps->a[end + 1] = ps->a[end];
// --end;
//}
//ps->a[0] = x;
//ps->size++;
插入的时候,可能容量会不足
SeqListInsert(ps, 0, x);//直接调用任意位置插入函数,将参数改为0,即可实现头插
}
10、头部删除
//头删
void SeqListPopFront(SL* ps)
{
//assert(ps->size > 0);
挪动数据
//int begin = 1;
//while (begin < ps->size)
//{
// ps->a[begin - 1] = ps->a[begin];
// ++begin;
//}
//ps->size--;
SeqListErase(ps, 0);//直接调用任意位置删除函数,把参数改为0,即可实现头删
}
11、查找数据
//查找指定数据
int SeqListFind(SL* ps, SLDataType x)
{
//当SLDataType是int 类型时的查找
int i = 0;
for (i = 0; i < ps->size; i++)
{
if (ps->a[i] == x)
{
return i;
}
}
return -1;
//当SLDataType是char 类型时的查找用strcmp
}
五、测试
1、TestSeqList1(测试尾插、尾删)
void TestSeqList1()
{
SL s1;
SeqListInit(&s1);//初始化
printf("尾插五个数字\n");
SeqListPushBack(&s1, 1);//尾插五个数
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
SeqListPrint(&s1);//打印一下
printf("尾删两个数\n");
SeqListPopBack(&s1);//尾删一个
SeqListPopBack(&s1);//再尾删一个
SeqListPrint(&s1);//打印一下
SeqListDestory(&s1);//销毁顺序表
}
2、TestSeqList2(测试头插、头删)
void TestSeqList2()
{
SL s1;
SeqListInit(&s1);//初始化
printf("尾插五个数\n");
SeqListPushBack(&s1, 1);//尾插几个数
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
SeqListPrint(&s1);//打印一下
printf("头插五个数\n");
SeqListPushFront(&s1, 1);//头插几个数
SeqListPushFront(&s1, 2);
SeqListPushFront(&s1, 3);
SeqListPushFront(&s1, 4);
SeqListPushFront(&s1, 5);
SeqListPrint(&s1);//打印一下
printf("头删两个数\n");
SeqListPopFront(&s1);//头删几个数据
SeqListPopFront(&s1);
SeqListPrint(&s1);//打印一下
SeqListDestory(&s1);//销毁顺序表
}
3、TestSeqList3(测试查找,指定位置增加和删除)
void TestSeqList3()
{
SL s1;
SeqListInit(&s1);//初始化
printf("在前四个位置,分别插入1、2、3、4\n");
SeqListInsert(&s1, 0, 1);//插入几个数据
SeqListInsert(&s1, 1, 2);
SeqListInsert(&s1, 2, 3);
SeqListInsert(&s1, 3, 4);
SeqListPrint(&s1);//打印一下
printf("在值为4的地方插入40\n");
int pos=SeqListFind(&s1, 4);//查找
if (pos != -1)
{
SeqListInsert(&s1, pos, 40);//插入
}
SeqListPrint(&s1);//打印一下
printf("删除下标为3、4的数\n");
SeqListErase(&s1, 4);//删除
SeqListErase(&s1, 3);//删除的是下标为3的数,其实是第四个数
SeqListPrint(&s1);//打印一下
printf("删除值为3的数\n");
pos = SeqListFind(&s1, 3);
if (pos != -1)
{
SeqListErase(&s1, pos);//删除的是值为3的数,不是按下标来算
}
SeqListPrint(&s1);//打印一下
SeqListDestory(&s1);//销毁顺序表
}
4、运行结果
六、源码
1、seqlist.h
#pragma once
//#define N 100
//typedef int SLDataType;//重定义一下数据类型,要修改时只需要将int改成char,double等等
//
静态顺序表
//typedef struct SeqList
//{
// SLDataType a[N];
// int size;//表示数组中存储了多少个有效数据,必须连着存
//}SL;
//
//
接口函数
//void SeqListInit(SL* ps, SLDataType x);//初始化
//void SeqListPushBack(SL* ps, SLDataType x);//尾插
//void SeqListPopBack(SL* ps);//尾删
//void SeqListPushFront(SL* ps, SLDataType x);//头插
//void SeqListPopFront(SL* ps);//头删
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLDataType;
//动态顺序表
typedef struct SeqList
{
SLDataType* a;
int size;//表示数组中存储了多少个有效数据,必须连着存
int capacity;//数组实际能存数据的空间容量是多大,指的是个数
}SL;
//接口函数
void SeqListInit(SL* ps);//初始化
void SeqListPrint(SL* ps);//打印
void SeqListDestory(SL* ps);//销毁
void SeqListCheckCapacity(SL* ps);//检测容量
void SeqListPushBack(SL* ps, SLDataType x);//在尾部插入数据
void SeqListPopBack(SL* ps);//删除尾部数据
void SeqListPushFront(SL* ps, SLDataType x);//在头部插入数据
void SeqListPopFront(SL* ps);//删除头部数据
int SeqListFind(SL* ps, SLDataType x);//查找指定数据
void SeqListInsert(SL* ps, int pos, SLDataType x);//在指定的位置插入数据
void SeqListErase(SL* ps, int pos);//在指定的位置删除数据
2、seqlist.c
#include "seqlist.h"
//初始化
void SeqListInit(SL* ps)
{
ps->a = NULL;
ps->size = 0;
ps->capacity = 0;
}
//打印
void SeqListPrint(SL* ps)
{
int i = 0;
for (i = 0; i < ps->size; i++)
{
printf("%d ", ps->a[i]);
}
printf("\n");
}
//销毁
void SeqListDestory(SL* ps)
{
free(ps->a);
ps->a = NULL;
ps->size = 0;
ps->capacity = 0;
}
//检测容量
void SeqListCheckCapacity(SL* ps)
{
//如果没有空间或者空间不足,就扩容
if (ps->size == ps->capacity)
{
//此时有两种情况,第一种是还没有空间,第二种是已经满了
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
//判断空间是否为0,如果为0,则开辟4个空间,如果不为0,则开辟当前空间的二倍的空间
SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));
//void* realloc(void* ptr,size_t size);
//realloc函数有一个特点,如果要增加的原数组空间大小为0,则功能类似于malloc函数,进行开辟
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);//exit直接退出程序,return只是退出这个函数
}
ps->a = tmp;
ps->capacity = newcapacity;
}
}
//在指定的位置插入数据
void SeqListInsert(SL* ps, int pos, SLDataType x)
{
//插入的位置要和之前的数据连续
//第一种
/*if (pos > ps->size || pos < 0)
{
printf("pos invalid\n");
return;
}*/
//第二种
assert(pos >= 0 && pos <= ps->size);
//挪动数据
SeqListCheckCapacity(ps);//检查一下容量
int end = ps->size - 1;
while (end >= pos)
{
ps->a[end + 1] = ps->a[end];
--end;
}
ps->a[pos] = x;
ps->size++;
}
//在指定的位置删除数据
void SeqListErase(SL* ps, int pos)
{
assert(pos >= 0 && pos < ps->size);
int begin = pos + 1;
while (begin < ps->size)
{
ps->a[begin - 1] = ps->a[begin];
++begin;
}
ps->size--;
}
//尾插
void SeqListPushBack(SL* ps, SLDataType x)
{
SeqListInsert(ps, ps->size, x);//调用一下任意插入函数,将参数改为ps->size即可实现尾插
}
//尾删
void SeqListPopBack(SL* ps)
{
第一种
///*if (ps->size > 0)
//{
// ps->size--;
//}*/
第二种
//assert(ps->size > 0);
//ps->size--;
SeqListErase(ps, ps->size-1);//直接调用任意位置删除函数,把参数改为ps->size-1,即可实现尾删
}
//头插
void SeqListPushFront(SL* ps, SLDataType x)
{
//SeqListCheckCapacity(ps);//检查下容量
挪动数据,把后面的往后移,再把数据插入到第一个位置
//int end = ps->size - 1;
//while (end >= 0)
//{
// ps->a[end + 1] = ps->a[end];
// --end;
//}
//ps->a[0] = x;
//ps->size++;
插入的时候,可能容量会不足
SeqListInsert(ps, 0, x);//直接调用任意位置插入函数,将参数改为0,即可实现头插
}
//头删
void SeqListPopFront(SL* ps)
{
//assert(ps->size > 0);
挪动数据
//int begin = 1;
//while (begin < ps->size)
//{
// ps->a[begin - 1] = ps->a[begin];
// ++begin;
//}
//ps->size--;
SeqListErase(ps, 0);//直接调用任意位置删除函数,把参数改为0,即可实现头删
}
//查找指定数据
int SeqListFind(SL* ps, SLDataType x)
{
//当SLDataType是int 类型时的查找
int i = 0;
for (i = 0; i < ps->size; i++)
{
if (ps->a[i] == x)
{
return i;
}
}
return -1;
//当SLDataType是char 类型时的查找用strcmp
}
3、test.c
#include "seqlist.h"
void TestSeqList1()
{
SL s1;
SeqListInit(&s1);//初始化
printf("尾插五个数字\n");
SeqListPushBack(&s1, 1);//尾插五个数
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
SeqListPrint(&s1);//打印一下
printf("尾删两个数\n");
SeqListPopBack(&s1);//尾删一个
SeqListPopBack(&s1);//再尾删一个
SeqListPrint(&s1);//打印一下
SeqListDestory(&s1);//销毁顺序表
}
void TestSeqList2()
{
SL s1;
SeqListInit(&s1);//初始化
printf("尾插五个数\n");
SeqListPushBack(&s1, 1);//尾插几个数
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
SeqListPrint(&s1);//打印一下
printf("头插五个数\n");
SeqListPushFront(&s1, 1);//头插几个数
SeqListPushFront(&s1, 2);
SeqListPushFront(&s1, 3);
SeqListPushFront(&s1, 4);
SeqListPushFront(&s1, 5);
SeqListPrint(&s1);//打印一下
printf("头删两个数\n");
SeqListPopFront(&s1);//头删几个数据
SeqListPopFront(&s1);
SeqListPrint(&s1);//打印一下
SeqListDestory(&s1);//销毁顺序表
}
void TestSeqList3()
{
SL s1;
SeqListInit(&s1);//初始化
printf("在前四个位置,分别插入1、2、3、4\n");
SeqListInsert(&s1, 0, 1);//插入几个数据
SeqListInsert(&s1, 1, 2);
SeqListInsert(&s1, 2, 3);
SeqListInsert(&s1, 3, 4);
SeqListPrint(&s1);//打印一下
printf("在值为4的地方插入40\n");
int pos=SeqListFind(&s1, 4);//查找
if (pos != -1)
{
SeqListInsert(&s1, pos, 40);//插入
}
SeqListPrint(&s1);//打印一下
printf("删除下标为3、4的数\n");
SeqListErase(&s1, 4);//删除
SeqListErase(&s1, 3);//删除的是下标为3的数,其实是第四个数
SeqListPrint(&s1);//打印一下
printf("删除值为3的数\n");
pos = SeqListFind(&s1, 3);
if (pos != -1)
{
SeqListErase(&s1, pos);//删除的是值为3的数,不是按下标来算
}
SeqListPrint(&s1);//打印一下
SeqListDestory(&s1);//销毁顺序表
}
int main()
{
printf("第一组测试\n");
TestSeqList1();//测试下 尾插、尾删
printf("\n");
printf("第二组测试\n");
TestSeqList2();//测试下 头插、头删
printf("\n");
printf("第三组测试\n");
TestSeqList3();//测试下 查找,指定位置增加和删除
printf("\n");
return 0;
}
七、优缺点
1、Merit
顺序表优点
1、支持随机访问(即通过下标直接访问第i个数据)
2、Shortcoming
顺序表的缺陷
- 空间不够了需要扩容,扩容代价比较大
- 为了避免频繁扩容,满了一般直接扩二倍,会造成一定的空间浪费
- 顺序表要求数据必须从开始位置连续存储,所以我们在头部或者中间位置插入或者删除数据,就需要挪动数据,效率不高