数据结构(1)-顺序表第一篇

1.顺序表的介绍 

顺序表是数据结构线性表的一种,其在物理结构和逻辑结构上都是连续的。

顺序表和数组有什么关联呢

顺序表的底层结构是数组,其本质上是对数组进行更加豪华的包装

如果拿路边的小饭店比作数组,那么顺序表就相当于米其林五星级酒店,他们对饭菜的加工和味道等都不一样,五星级的看起来就更加的豪华。

2.顺序表的分类 

 顺序表也是有分类的

分为:静态顺序表和动态顺序表两大类

静态顺序表

从字面意思上能看出,能够储存的数据是固定大小的,无法改变 

其实现的代码:

struct std {
	int arr[100]; //  当然这里不一定是int类型的,也可以是其他类型的
	int size;
};

很明显的能够看出静态顺序表的缺点,因为其空间大小是固定的,所以会造成空间大小不足或者是空间大小过剩等情况,而动态顺序表就能很好的避免这些问题。

 动态顺序表可以按需向系统申请空间,当空间不足时自主的向系统申请空间,申请内存空间时通常会以原有空间的2-3倍来申请空间,下面就自主实现一个动态顺序表

3.动态顺序表的实现 

 实现动态顺序表需要我们有一个头文件和两个源文件

对使用函数进行声明的头文件--seqlist.h

实现需要使用的函数的源文件--seqlist.c

对编写的动态顺序表进行测试的源文件--test.c

首先先在 seqlist.h 文件中创造出动态顺序表的主体

typedef int SLDataType;
//顺序表储存的数据类型不一定是int类型,typedef 可以帮助我们后续修改储存的数据类型
struct SeqList {
	SLDataType* arr; // 用来储存数据
	int data_size; // 顺序表中储存数据的有效个数
	int space_size; // 顺序表空间的大小
};

 接下来我们要对顺序表进行操作,让其更加完善:

     顺序表的初始化

     对顺序表进行扩容

     从尾部插入删除数据

     从头部插入删除数据

     从指定位置插入删除数据

     打印顺序表

     顺序表的销毁

先在 test.c 中创建需要的代码 

void test_01()
{
	SL sl;
}

int main()
{
	test_01();
	return 0;
}

(1)顺序表的初始化

void SL_init(SL* ps) {
	ps->arr = NULL;
	ps->data_size = ps->space_size = 0;
}

(2)对顺序表进行扩容

void SL_extend(SL* ps) {
	//先检查空间是否足够,不够就申请增加空间
	if (ps->data_size == ps->space_size) {
		int new_space_size = ps->space_size == 0 ? 4 : 2 * ps->space_size;
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, new_space_size * sizeof(SLDataType));
		//检查空间是否成功申请
        //这里也可以直接使用assert断言
		if (tmp == NULL) {
			perror("realloc");// 未成功申请就报错
			exit(1);//并退出
		}
		//申请成功后就使用
		ps->arr = tmp;
		ps->space_size = new_space_size;
	}
}

(3)插入数据

①从头部插入数据:

从头部插入数据需要将所有的数据都向后移一位再插入

void SL_addfront(SL* ps, SLDataType x) {
	assert(ps);
	SL_extend(ps);
	// 先让整体数据都向后移动一位
	for (int i = ps->data_size; i > 0; i--) {
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[0] = x;
	ps->data_size++;
}
②从尾部插入数据 :

直接从尾部插入数据就行

void SL_addback(SL* ps, SLDataType x) {
	assert(ps);
	SL_extend(ps);//检查空间是否足够
	ps->arr[ps->data_size] = x;//把x放到尾部位置
	ps->data_size++;//插入数据后有效数据也加1
}
③从指定位置插入数据:

插入位置及后面的数据都要向后移一位 

void SL_addcust(SL* ps, int pos, SLDataType x) {
	assert(ps);
	SL_extend(ps);
	//插入位置及后面的数据都要向后移一位 
	for (int i = ps->data_size; i > pos; i--) {
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	ps->data_size++;
}

 (4)删除数据:

①从头部删除数据:

删除第一个数据后,需要把后面的数据都向前移一位 

void SL_delfront(SL* ps) {
	assert(ps);
	assert(ps->data_size);//删除数据时数据表不能为空
	for (int i = 0; i < ps->data_size - 2; i++) {
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->data_size--;
}
②从尾部删除数据 
void SL_delback(SL* ps) {
	assert(ps);
	assert(ps->data_size);
	ps->data_size--;
}
③从指定位置删除数据:

删除后需要把删除的数据后面的数据全部向前移动一位 

void SL_delcust(SL* ps, int pos) {
	assert(ps);
	assert(ps->data_size);
	for (int i = pos; i < ps->data_size - 1; i++) {
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->data_size--;
}

(5)打印顺序表中的数据 

void SL_print(SL* ps) {
	assert(ps);
	for (int i = 0; i < ps->data_size; i++) {
		printf("%d ", ps->arr[i]);
	}
    print("\n");
}

(6)顺序表的销毁 

void SL_destroy(SL* ps) {
	assert(ps);
	free(ps->arr);
	ps->arr = NULL;
	ps->data_size = ps->space_size = 0;
}

 这样一来,我们一整个完整的顺序表就制作完成了

4.顺序表的测试

 (1)添加元素的测试

void test_01()
{
	SL sl;
	//初始化
	SL_init(&sl);
	//添加元素(这里是从尾部添加元素)
	SL_addback(&sl, 1);
	SL_addback(&sl, 2);
	SL_addback(&sl, 3);
	SL_addback(&sl, 4);
	SL_print(&sl);
	//销毁
	SL_destroy(&sl);
}
int main()
{
	test_01();
	return 0;
}

打印的结果

1 2 3 4

接下来我们要把先把6加在2和3之间,再把0加在首元素位置处,最后把5加在末尾处 

void test_01()
{
	SL sl;
	//初始化
	SL_init(&sl);
	//添加元素(这里是从尾部添加元素)
	SL_addback(&sl, 1);
	SL_addback(&sl, 2);
	SL_addback(&sl, 3);
	SL_addback(&sl, 4);
	SL_print(&sl);
    SL_addcust(&sl, 2, 6);
	SL_addfront(&sl, 0);
	SL_addback(&sl, 5);
	SL_print(&sl);
	//销毁
	SL_destroy(&sl);
}

 打印的结果为

1 2 3 4
0 1 2 6 3 4 5

 (2)删除元素的测试

接着上面的代码,分别吧0 6 5删除 

void test_01()
{
	SL sl;
	//初始化
	SL_init(&sl);
	//添加元素(这里是从尾部添加元素)
	SL_addback(&sl, 1);
	SL_addback(&sl, 2);
	SL_addback(&sl, 3);
	SL_addback(&sl, 4);
	SL_print(&sl);
	SL_addcust(&sl, 2, 6);
	SL_addfront(&sl, 0);
	SL_addback(&sl, 5);
	SL_print(&sl);
	SL_delfront(&sl);
	SL_delback(&sl);
	SL_delcust(&sl, 2);
	SL_print(&sl);
	//销毁
	SL_destroy(&sl);
}

打印的结果 

1 2 3 4
0 1 2 6 3 4 5 
1 2 3 4

 这样一来,我们整个代码的就完成了,测试也没有问题,

5.顺序表的全部代码

(1)Seqlist.h

#pragma once
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>

typedef int SLDataType;
//顺序表储存的数据类型不一定是int类型,typedef 可以帮助我们后续修改储存的数据类型
struct SeqList {
	SLDataType* arr; // 用来储存数据
	int data_size; // 顺序表中储存数据的有效个数
	int space_size; // 顺序表空间的大小
};
typedef struct SeqList SL;

// 对顺序表进行初始化
void SL_init(SL* ps);
// 对顺序表进行空间扩容
void SL_extend(SL* ps);
// 从尾部对顺序表添加元素
void SL_addback(SL* ps, SLDataType x);
// 从头部对顺序表添加元素
void SL_addfront(SL* ps, SLDataType x);
// 从指定位置对顺序表添加元素
void SL_addcust(SL* ps, int pos, SLDataType x);
// 删除头部元素
void SL_delfront(SL* ps);
// 删除尾部元素
void SL_delback(SL* ps);
// 删除指定位置的元素
void SL_delcust(SL* ps, int pos);
// 打印顺序表中的元素
void SL_print(SL* ps);
// 销毁顺序表
void SL_destroy(SL* ps);

(2)Seqlist.c

#define _CRT_SECURE_NO_WARNINGS 1

#include"Seqlist.h"

void SL_init(SL* ps) {
	ps->arr = NULL;
	ps->data_size = ps->space_size = 0;
}

void SL_extend(SL* ps) {
	//先检查空间是否足够,不够就申请增加空间
	if (ps->data_size == ps->space_size) {
		int new_space_size = ps->space_size == 0 ? 4 : 2 * ps->space_size;
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, new_space_size * sizeof(SLDataType));
		//检查空间是否成功申请
		if (tmp == NULL) {
			perror("realloc");// 未成功申请就报错
			exit(1);//并退出
		}
		//申请成功后就使用
		ps->arr = tmp;
		ps->space_size = new_space_size;
	}
}

void SL_addback(SL* ps, SLDataType x) {
	assert(ps);
	SL_extend(ps);//检查空间是否足够
	ps->arr[ps->data_size] = x;//把x放到尾部位置
	ps->data_size++;//插入数据后有效数据也加1
}

void SL_addfront(SL* ps, SLDataType x) {
	assert(ps);
	SL_extend(ps);
	// 先让整体数据都向后移动一位
	for (int i = ps->data_size; i > 0; i--) {
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[0] = x;
	ps->data_size++;
}

void SL_addcust(SL* ps, int pos, SLDataType x) {
	assert(ps);
	SL_extend(ps);
	//插入位置及后面的数据都要向后移一位?
	for (int i = ps->data_size; i > pos; i--) {
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	ps->data_size++;
}

void SL_delfront(SL* ps) {
	assert(ps);
	assert(ps->data_size);//删除数据时数据表不能为空
	for (int i = 0; i < ps->data_size - 2; i++) {
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->data_size--;
}

void SL_delback(SL* ps) {
	assert(ps);
	assert(ps->data_size);
	ps->data_size--;
}

void SL_delcust(SL* ps, int pos) {
	assert(ps);
	assert(ps->data_size);
	for (int i = pos; i < ps->data_size - 1; i++) {
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->data_size--;
}

void SL_print(SL* ps) {
	assert(ps);
	for (int i = 0; i < ps->data_size; i++) {
		printf("%d ", ps->arr[i]);
	}
	printf("\n");
}

void SL_destroy(SL* ps) {
	assert(ps);
	free(ps->arr);
	ps->arr = NULL;
	ps->data_size = ps->space_size = 0;
}

(3)test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"Seqlist.h"

void test_01()
{
	SL sl;
	//初始化
	SL_init(&sl);
	//添加元素(这里是从尾部添加元素)
	SL_addback(&sl, 1);
	SL_addback(&sl, 2);
	SL_addback(&sl, 3);
	SL_addback(&sl, 4);
	SL_print(&sl);
	SL_addcust(&sl, 2, 6);
	SL_addfront(&sl, 0);
	SL_addback(&sl, 5);
	SL_print(&sl);
	SL_delfront(&sl);
	SL_delback(&sl);
	SL_delcust(&sl, 2);
	SL_print(&sl);
	//销毁
	SL_destroy(&sl);
}
int main()
{
	test_01();
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值