顺序表:用一段连续的物理地址储存单元来一次存储数元素的线性结构,使用数组存储,并完成数据的增删改查。
1 静态顺序表
#define N 10
// 静态顺序表
// 顺序表的容量,是在静态时期确定(编译期间,代码里写死)
typedef struct SeqList {
int array[N]; // 定常数组容量是 100
int size; // 顺序表实际存储的数据个数
} SeqList;
2 动态顺序表
//动态顺序表
//初始化自动分配内存,自动扩容
typedef struct SeqList
{
int* array; //指向动态开辟的数组
int size; //有效数据个数
int capacity; //顺序表容量
} SeqList;
3 接口实现(C)
静态顺序表由于容量固定,使用起来会出现空间浪费或者空间不足的问题。而动态顺序表可随时根据实际需要扩容,方便实际使用,下面是动态顺序表的接口实现。
头文件(SeqList.h)
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#pragma once
#define SZ 10
//动态顺序表
//初始化自动分配内存,自动扩容
typedef struct SeqList
{
int* array;
int size; //有效数据个数
int capacity; //顺序表容量
}SeqList;
SeqList g_ps;
//顺序表初始化
void SeqListInit(SeqList* ps, int capacity);
//检查扩容
void CheckSeqListCap(SeqList* ps);
//插入、指定删除、指定查找、制定更改 输入数据函数
int InputDates(SeqList* ps);
//增
void SeqListPushBack(SeqList* ps, int v); //尾插
void SeqListPushFront(SeqList* ps, int v); //头插
void SeqListInsert(SeqList* ps, int v, int pos); //从指定位置插入
//删
void SeqListPopBack(SeqList* ps); //尾删
void SeqListPopFront(SeqList* ps); //头删
void SeqListErase(SeqList* ps, int pos); //从指定位置删除
//查
int SeqListFind(SeqList* ps, int v); //查找顺序表指定数
int SeqListBinaryFind(SeqList* ps, int v); //二分法查找顺序标准指定数
//改
void SeqListModify(SeqList* ps, int pos, int v); //更改顺序表中某个数
//打印
void SeqListPrint(SeqList* ps); //打印顺序表中的所有数
//指定删
void SeqListRemove(SeqList* ps, int v); //删除顺序表中第一个遇到的V
void SeqListRemoveAll(SeqList* ps, int v); //删除顺序表中的所有的V
//排序
void SeqListBubbleSort(SeqList* ps); //冒泡排序顺序表中的数字
//销毁顺序表
void SeqListDestory(SeqList* ps);
主函数(main.c)
#include "SeqList.h"
int Mune()
{
printf("========================\n");
printf("1.尾插\n");
printf("2.头插\n");
printf("3.指定位置插\n");
printf("4.尾删\n");
printf("5.头删\n");
printf("6.指定位置删\n");
printf("7.普通查找\n");
printf("8.二分查找\n");
printf("9.更改数据\n");
printf("10.打印\n");
printf("11.指定删除第一个V\n");
printf("12.指定删除所有V\n");
printf("13.冒泡排序\n");
printf("14.销毁顺序表\n");
printf("0.退出!\n");
printf("=======================\n");
int i = 0;
printf("请输入要执行函数代号:");
scanf("%d", &i);
return i;
}
int main()
{
//表驱动 为减少时间复杂度
//是一种使你可以在表中查找信息,而不必用很多的逻辑语句(if或Case)来把它们找出来的方法
typedef void(*pfunc_t)(SeqList*);
pfunc_t pfunc_table[] = {
//增
SeqListPushBack, //尾插
SeqListPushFront, //头插
SeqListInsert, //从指定位置插入
//删
SeqListPopBack, //尾删
SeqListPopFront, //头删
SeqListErase, //从指定位置删除
//查
SeqListFind, //查找顺序表指定数
SeqListBinaryFind, //二分法查找顺序标准指定数
//改
SeqListModify, //更改顺序表中某个数
//打印
SeqListPrint, //打印顺序表中的所有数
//指定删
SeqListRemove, //删除顺序表中第一个遇到的V
SeqListRemoveAll, //删除顺序表中的所有的V
//排序
SeqListBubbleSort, //冒泡排序顺序表中的数字
//销毁
SeqListDestory
};
SeqListInit(&g_ps, SZ);
while (1)
{
int choice = Mune();
if (choice < 0 || choice > 15)
{
printf("输入不合法,重新输入!\n");
continue;
}
if (choice == 0)
{
printf("退出!\n");
return;
}
//表驱动查找 []表中具体函数,()调用
pfunc_table[choice - 1](&g_ps);
printf("\n");
printf("\n");
}
system("pause");
return 0;
}
功能实现函数(SeqList.c)
#include "SeqList.h"
//顺序表初始化
void SeqListInit(SeqList* ps, int capacity)
{
assert(ps != NULL);
if (ps == NULL)
{
return;
}
ps->array = malloc(sizeof(int) * capacity);
assert(ps->array != NULL);
ps->size = 0;
ps->capacity = capacity;
}
//检查扩容
void CheckSeqListCap(SeqList* ps)
{
assert(ps != NULL);
if (ps->size < ps->capacity)
{
return; //不需要扩容
}
//需要扩容
int newcapacity = ps->capacity * 2; //一般扩容的空间大小为老空间的二倍大
int* newarray = (int*)malloc(sizeof(int) * newcapacity);
assert(newarray != NULL);
//把老空间里的内容移到新空间
for (int i = 0; i < ps->size; i++)
{
newarray[i] = ps->array[i];
}
//释放老空间 绑定新空间
free(ps->array);
ps->capacity = newcapacity;
ps->array = newarray;
}
int InputDates(SeqList* ps)
{
printf("请输入要 插入/指定删除/指定更改/的 新数据 或 位置:\n");
int v = 0;
printf("v = ");
scanf("%d", &v);
return v;
}
//增
void SeqListPushBack(SeqList* ps, int v) //尾插
{
assert(ps != NULL);
CheckSeqListCap(ps); //判断容量
//输入数据
v = InputDates(ps);
//尾插
ps->array[ps->size] = v; //array中最后一个位置
ps->size++;
printf("数据总量:%d", ps->size);
}
void SeqListPushFront(SeqList* ps, int v) //头插
{
assert(ps != NULL);
CheckSeqListCap(ps);
//输入数据
v = InputDates(ps);
//把表中数据从最后一个开始向后移动一个位置
//空出来首位
for (int i = ps->size; i >= 1; i--)
{
ps->array[i] = ps->array[i - 1];
}
//第一个位置插入
ps->array[0] = v;
ps->size++;
}
void SeqListInsert(SeqList* ps, int v, int pos) //从指定位置插入
{
assert(ps != NULL);
assert(ps->size > 0);
CheckSeqListCap(ps);
//输入数据
v = InputDates(ps);
//输入要插入的位置
pos = InputDates(ps);
//i代表空间的序号
for (int i = ps->size; i > pos; i--)
{
ps->array[i] = ps->array[i - 1];
}
ps->array[pos] = v;
ps->size++;
}
//删
void SeqListPopBack(SeqList* ps) //尾删
{
assert(ps != NULL);
assert(ps->size > 0);
ps->size--;
}
void SeqListPopFront(SeqList* ps) //头删
{
assert(ps != NULL);
assert(ps->size > 0);
//依次向前移,把第一个位置覆盖
for (int i = 0; i <= ps->size - 2; i++)
{
ps->array[i] = ps->array[i + 1];
}
ps->size--;
}
void SeqListErase(SeqList* ps, int pos) //从指定位置删除
{
assert(ps != NULL);
assert(ps->size > 0);
//assert(pos >= 0 && pos < ps->size);
//输入要插入的位置
pos = InputDates(ps);
//i代表空间的下标
for (int i = pos; i < ps->size - 1; i++)
{
ps->array[i] = ps->array[i + 1];
}
ps->size--;
}
//查
int SeqListFind(SeqList* ps, int v) //查找顺序表指定数
{
assert(ps->size > 0);
for (int i = 0; i < ps->size; i++)
{
if (ps->array[i] == v)
{
return i;
}
}
return -1;
}
//只能针对有序数组,即排序后的数组进行查找
int SeqListBinaryFind(SeqList* ps, int v) //二分法查找顺序标准指定数
{
assert(ps->size > 0);
//输入数据
v = InputDates(ps);
int left = 0;
int right = ps->size - 1;
while (left <= right)
{
int mid = (left + right) / 2;
if (ps->array[mid] == v)
{
printf("二分法查找到数字的下标为:%d", mid);
return mid;
}
else if (ps->array[mid] > v)
{
right = mid - 1;
}
else
{
left = mid + 1;
}
}
return -1;
}
//改
void SeqListModify(SeqList* ps, int pos, int v) //更改顺序表中某个数
{
assert(ps->size > 0);
//输入数据
v = InputDates(ps);
//输入要插入的位置
pos = InputDates(ps);
ps->array[pos] = v;
}
//打印
void SeqListPrint(SeqList* ps) //打印顺序表中的所有数
{
assert(ps->size > 0);
for (int i = 0; i < ps->size; i++)
{
printf("%d\t", ps->array[i]);
}
}
//指定删
void SeqListRemove(SeqList* ps, int v) //删除顺序表中第一个遇到的V
{
assert(ps->size > 0);
//输入数据
v = InputDates(ps);
//先找到v的位置返回值i
int pos = SeqListFind(ps, v);
if (pos == -1)
{
return;
}
//借助删除指定位置数据的函数
SeqListErase(ps, pos);
}
void SeqListRemoveAll(SeqList* ps, int v) //删除顺序表中的所有的V
{
assert(ps->size > 0);
//输入数据
v = InputDates(ps);
int i, j;
for (i = 0, j = 0; i < ps->size; i++)
{
if (ps->array[i] != v)
{
//把所有是v的位置都覆盖了,v自然就全删了
ps->array[j] = ps->array[i];
j++;
}
}
ps->size = j; //数据总量就是j
}
//排序
void SeqListBubbleSort(SeqList* ps) //冒泡排序顺序表中的数字
{
assert(ps->size > 0);
for (int i = 0; i < ps->size; i++)
{
int sorted = 1; //优化算法
for (int j = 0; j < ps->size - i - 1; j++) //O(n^2)
{
if (ps->array[j] > ps->array[j + 1])
{
int tmp = 0;
tmp = ps->array[j + 1];
ps->array[j + 1] = ps->array[j];
ps->array[j] = tmp;
sorted = 0;
}
}
if (sorted == 1)
{
return;
}
}
}
void SeqListDestory(SeqList* ps) //销毁顺序表
{
assert(ps != NULL);
assert(ps->size > 0);
//array为空时 直接退出
if (ps->array == NULL)
{
printf("顺序表中没有值!\n");
return;
}
//释放申请空间 数据 容量初始为0
free(ps->array);
ps->array = NULL;
ps->capacity = 0;
ps->size = 0;
}
存在问题:
不同插入时,空间复杂度O(n)不同。
扩容时,造成空间消耗。
扩容一般是空间成倍增长,有可能导致空间浪费。