C语言数据结构——顺序表


前言

本篇文章主要是带领大家用C语言实现动态顺序表

 


一、结构体创建及其初始化

//顺序表结构体创建
struct SeqList
{
	SLDataType* sl;
	int size;
	int capacity;
}SL;
//初始化
void SLInit(struct SeqList* ps)
{
	ps->sl = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

ps:SLDataType是#define定义的顺序表的数据类型,这里我们用的是int

#define SLDataType int

二、顺序表打印

//顺序表打印
void Print(struct SeqList* ps)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d", ps->sl[i]);
	}
	printf("\n");
}

三、扩容函数

由于我们写的是动态顺序表,所以需要用到malloc,realloc等动态内存管理函数来进行动态扩容,因此我们专门写了一个扩容函数进行扩容。

//扩容函数
void SLDila(struct SeqList* ps)
{
	if (ps->size == ps->capacity)
	{
		int Newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;//判断是否已经开辟空间,没有则开辟四个SLDataType的空间
		SLDataType* ptr = realloc(ps->sl, Newcapacity * sizeof(SLDataType));
		if (ptr == NULL)
		{
			perror("ralloc");
			exit(-1);
		}
		ps->sl = ptr;
		ps->capacity = Newcapacity;
	}
}

四、尾插/尾删

尾插:即从顺序表末尾将数据插入进去

//顺序表尾插
void SLPushBack(struct SeqList* ps, SLDataType x)
{
	SLDila(ps);
	ps->sl[ps->size] = x;
	ps->size++;
}

尾删:由于我们是靠size读取写入的数字,所以没必要将最后一位挪走或者初始化,直接size--即可

void SLPopBack(struct SeqList* ps)
{
	assert(ps->size);//如果size为0则没有要删除的内容,直接报错
	ps->size--;
}

五、首插/首删

首插:从头部的位置插入数据,由于从头部插入我们需要挪数据,我们采用的是从后往前挪的办法,如下图所示:

 

//顺序表首插
void SLPushFront(struct SeqList* ps, SLDataType x)
{
	assert(ps);
	SLDila(ps);
	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->sl[end + 1] = ps->sl[end];
		end--;
	}
	ps->sl[0] = x;
	ps->size++;
}

首删:和首插相反,从前往后挪

//顺序表首删
void SLPopFront(struct SeqList* ps)
{
	assert(ps);
	assert(ps->size > 0);
	int begin = 0;
	while (begin < ps->size-1)
	{
		ps->sl[begin] = ps->sl[begin+1];
		begin++;
	}
	ps->size--;
}

 六、中间插入/中间删除/查找数字

中间插入:输入坐标,将数据插入到坐标位置,方法与首插类似

//顺序表中间插入
void SLInsert(struct SeqList* ps, int a, SLDataType x)
{
	assert(ps);
	assert(a >= 0 && a <= ps->size);
	SLDila(ps);

	int end = ps->size-1;
	while (end>=a)
	{
		ps->sl[end + 1] = ps->sl[end];
		end--;
	}
	ps->sl[a] = x;
	ps->size++;
}

中间删除:方法和首删类似

//顺序表中间删除
void SLErase(struct SeqList* ps, int a)
{
	assert(ps);
	assert(a >= 0 && a < ps->size);
	int begin = a;
	while (begin < ps->size)
	{
		ps->sl[begin] = ps->sl[begin + 1];
		begin++;
	}
	ps->size--;

}

查找数字:输入要查找的数字,找到返回下标,未找到返回-1

//查找目标数
int SLFind(struct SeqList* ps, SLDataType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->sl[i] == x)
		{
			return i;
		}
	}
	printf("未找到该数字");
	return -1;
}

七、退出销毁及菜单

销毁:

//顺序表销毁
void SLDestroy(struct SeqList* ps)
{
	free(ps->sl);
	ps->sl = NULL;
}

菜单:

void menu()
{
	printf("*******************************\n");
	printf("****1.尾部插入  2.尾部删除 ****\n");
	printf("****3.头部插入  4.头部删除 ****\n");
	printf("****5.中间插入  6.中间删除 ****\n");
	printf("****7.打印      0.退出     ****\n");
	printf("*******************************\n");

}

八、效果演示

 九、代码

SeqList.h

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define SLDataType int

//顺序表结构体创建
struct SeqList
{
	SLDataType* sl;
	int size;
	int capacity;
}SL;

//初始化
void SLInit(struct SeqList* ps);
//顺序表打印
void Print(struct SeqList* ps);
//顺序表尾插
void SLPushBack(struct SeqList* ps, SLDataType x);//x是要插进去的数字
//顺序表尾删
void SLPopBack(struct SeqList* ps);
//顺序表销毁
void SLDestroy(struct SeqList* ps);
//扩容函数
void SLDila(struct SeqList* ps);
//顺序表首插
void SLPushFront(struct SeqList* ps, SLDataType x);
//顺序表首删
void SLPopFront(struct SeqList* ps);
//顺序表中间插入
void SLInsert(struct SeqList* ps, int a, SLDataType x);
//顺序表中间删除
void SLErase(struct SeqList* ps, int a);
//查找目标数
int SLFind(struct SeqList* ps, SLDataType x);

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
void menu()
{
	printf("*******************************\n");
	printf("****1.尾部插入  2.尾部删除 ****\n");
	printf("****3.头部插入  4.头部删除 ****\n");
	printf("****5.中间插入  6.中间删除 ****\n");
	printf("****7.打印      0.退出     ****\n");
	printf("*******************************\n");

}
int main()
{
	menu();
	SLInit(&SL);
	int input;
	do
	{
		printf("请选择:");
		scanf("%d", &input);
		switch(input)
		{
		case 1:
			printf("请输入要写入的数字:");
			SLDataType i;
			scanf("%d", &i);
			SLPushBack(&SL, i);
			break;
		case 2:
			SLPopBack(&SL);
			break;
		case 3:
			printf("请输入要写入的数字:");
			SLDataType a;
			scanf("%d", &a);
			SLPushFront(&SL, a);
			break;
		case 4:
			SLPopFront(&SL);
			break;
		case 5:
			printf("请输入要写入的数字及下标:");
			SLDataType b;
			int j;
			scanf("%d %d", &b,&j);
			SLInsert(&SL, j, b);
			break;
		case 6:
			printf("请输入要删除的数字:");
			int c;
			scanf("%d", &c);
			int ret = SLFind(&SL, c);
			if (ret != -1)
			{
				SLErase(&SL, ret);
			}
			else
			{
				printf("未找到该数字");
			}
			break;
		case 7:
			Print(&SL);
			break;
		case 0:
			printf("退出");
			SLDestroy(&SL);
			break;
		default:
			printf("输入错误,请重新输入");
			break;
		}

	} while (input);
	return 0;
}

SeqList.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
//扩容函数
void SLDila(struct SeqList* ps)
{
	if (ps->size == ps->capacity)
	{
		int Newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;//判断是否已经开辟空间,没有则开辟四个SLDataType的空间
		SLDataType* ptr = realloc(ps->sl, Newcapacity * sizeof(SLDataType));
		if (ptr == NULL)
		{
			perror("ralloc");
			exit(-1);
		}
		ps->sl = ptr;
		ps->capacity = Newcapacity;
	}
}
//初始化
void SLInit(struct SeqList* ps)
{
	ps->sl = NULL;
	ps->size = 0;
	ps->capacity = 0;
}
//顺序表打印
void Print(struct SeqList* ps)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d", ps->sl[i]);
	}
	printf("\n");
}
//顺序表尾插
void SLPushBack(struct SeqList* ps, SLDataType x)
{
	SLDila(ps);
	ps->sl[ps->size] = x;
	ps->size++;
}
//顺序表尾删
void SLPopBack(struct SeqList* ps)
{
	assert(ps->size);//如果size为0则没有要删除的内容,直接报错
	ps->size--;
}
//顺序表销毁
void SLDestroy(struct SeqList* ps)
{
	free(ps->sl);
	ps->sl = NULL;
}
//顺序表首插
void SLPushFront(struct SeqList* ps, SLDataType x)
{
	assert(ps);
	SLDila(ps);
	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->sl[end + 1] = ps->sl[end];
		end--;
	}
	ps->sl[0] = x;
	ps->size++;
}
//顺序表首删
void SLPopFront(struct SeqList* ps)
{
	assert(ps);
	assert(ps->size > 0);
	int begin = 0;
	while (begin < ps->size-1)
	{
		ps->sl[begin] = ps->sl[begin+1];
		begin++;
	}
	ps->size--;
}
//顺序表中间插入
void SLInsert(struct SeqList* ps, int a, SLDataType x)
{
	assert(ps);
	assert(a >= 0 && a <= ps->size);
	SLDila(ps);

	int end = ps->size-1;
	while (end>=a)
	{
		ps->sl[end + 1] = ps->sl[end];
		end--;
	}
	ps->sl[a] = x;
	ps->size++;
}
//顺序表中间删除
void SLErase(struct SeqList* ps, int a)
{
	assert(ps);
	assert(a >= 0 && a < ps->size);
	int begin = a;
	while (begin < ps->size)
	{
		ps->sl[begin] = ps->sl[begin + 1];
		begin++;
	}
	ps->size--;

}
//查找目标数
int SLFind(struct SeqList* ps, SLDataType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->sl[i] == x)
		{
			return i;
		}
	}
	printf("未找到该数字");
	return -1;
}


总结

以上就是顺序表的全部内容,希望铁子们能够有所收获。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值