顺序表 解释和接口实现(C语言)(线性表--Date struct)

顺序表:用一段连续的物理地址储存单元来一次存储数元素的线性结构,使用数组存储,并完成数据的增删改查。

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)不同。

扩容时,造成空间消耗。

扩容一般是空间成倍增长,有可能导致空间浪费。

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值