您现在的位置是:首页 >其他 >数据结构初阶--顺序表的基本操作网站首页其他

数据结构初阶--顺序表的基本操作

偷吃橙子的喵 2023-05-19 08:00:03
简介数据结构初阶--顺序表的基本操作

前言

本篇文章我们将对顺序表的一些基本操作进行讲解

创建顺序表

我们先创建一个动态内存存储的顺序表(SeqList.h)

//创建顺序表
typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* a;//动态开辟数组
	int size;//存储顺序表中有效数据的个数
	int capacity;//存储空间个数-->记录最大容量
}SeqList;

初始化顺序表

创建完顺序表后我们就要对顺序表中的数据进行初始化。(SeqList.c)

//初始化顺序表
void SeqListInit(SeqList* ps1)
{
	assert(ps1);
	ps1->a = NULL;
	ps1->size = 0;
	ps1->capacity = 0;
}

检测是否需要扩容

因为每次在插入数据时,都可能存在顺序表已满的情况,所以我们需要在每次对顺序表进行增添时对此时的数据个数进行判断,即将当前的size与capacity比较,不够则扩容。(SeqList.c)

//检测是否需要扩容
void SeqListCheckCapacity(SeqList* ps1)
{
	assert(ps1);
	//如果满了就需要扩容
	if (ps1->size == ps1->capacity)
	{
		size_t newCapacity = ps1->capacity == 0 ? 4 : ps1->capacity * 2;//防止最大数据个数本身就是0的情况
		SLDataType* tmp = realloc(ps1->a, sizeof(SLDataType) * newCapacity);
		if (tmp == NULL)
		{
			printf("realloc fail
");
			exit(-1);
		}
		else
		{
			ps1->a = tmp;
			ps1->capacity = (int)newCapacity;
		}
	}
}

打印顺序表

(SeqList.c)

//打印顺序表
void SeqListPrint(SeqList* ps1)
{
	assert(ps1);
	for (int i = 0; i < ps1->size; i++)
	{
		printf("%d ", ps1->a[i]);
	}
	printf("
");
}

销毁顺序表

由于内存是动态开辟的,所以在最后我们需要将内存释放(SeqList.c)

//销毁顺序表
void SeqListDestroy(SeqList* ps1)
{
	assert(ps1);
	free(ps1->a);
	ps1->a = NULL;
	ps1->capacity = ps1->size = 0;
}

尾插

顾名思义,就是在顺序表末尾插入数据(SeqList.c)

//尾插
void SeqListPushBack(SeqList* ps1, SLDataType x)
{
	assert(ps1);
	//法1
	//先检查容量
	SeqListCheckCapacity(ps1);
	ps1->a[ps1->size] = x;
	ps1->size++;
}

尾删

(SeqList.c)

//尾删
void SeqListPopBack(SeqList* ps1)
{
	assert(ps1);
	//法1
	if (ps1->size > 0)
	{
		ps1->size--;
	}
}

头插

顾名思义,就是在顺序表开头插入数据(SeqList.c)

//头插
void SeqListPushFront(SeqList* ps1, SLDataType x)
{
	assert(ps1);
	//法1
	//先检查容量
	SeqListCheckCapacity(ps1);
	int end = ps1->size - 1;
	while (end >= 0)
	{
		ps1->a[end + 1] = ps1->a[end];
		end--;
	}
	ps1->a[0] = x;
	ps1->size++;
}

头删

(SeqList.c)

//头删
void SeqListPopFront(SeqList* ps1)
{
	assert(ps1);
	//法1
	if (ps1->size > 0)
	{
		int begin = 1;
		while (ps1->size > begin)
		{
			ps1->a[begin - 1] = ps1->a[begin];
			begin++;
		}
	}
}

在pos位置插入x

在pos插入数据x,即要将pos位置后的数据都向后移动一位,所以我们首先就要检查内存,然后值得留意的是,我们应该从最后开始依次挪动数据,如果从前往后挪动数据,会导致后一个数据被前一个数据覆盖(SeqList.c)

//在pos位置插入x
void SeqListInsert(SeqList* ps1, size_t pos, SLDataType x)
{
	assert(ps1);
	//检查pos是否越界?
	// 暴力检查assert
	assert(ps1->size >= pos && ps1);
	//检查容量
	SeqListCheckCapacity(ps1);
	//插入数据
	int end = ps1->size - 1;
	while (end >= (int)pos)
	{
		ps1->a[end + 1] = ps1->a[end];
		end--;
	}
	ps1->a[pos] = x;
	ps1->size++;
}

我们思考,头插和尾插是不是一种特殊的下标插入(一个是0,一个是ps1->size-1)。所以我们可以将这个函数调用进头插,尾插的函数中去。

删除pos位置的数据

我们可以通过将后一个数据覆盖掉前一个数据的方法来实现删除。(SeqList.c)

//删除pos位置的数据
void SeqListErase(SeqList* ps1, size_t pos)
{
	assert(ps1);
	assert(ps1->size > pos && pos);
	size_t begin = pos + 1;
	while (begin < ps1->size)
	{
		ps1->a[begin - 1] = ps1->a[begin];
		begin++;
	}
	ps1->size--;
}

同样的,头删和尾删也是一种特殊的特殊的下标删除(一个是0,一个是ps1->size-1),我们同样可以将这个函数调用进头插,尾插的函数中去。

查找指定数据

(SeqList.c)

//查找指定数字
int SeqListFind(SeqList* ps1, SLDataType x)
{
	assert(ps1);
	for (int i = 0; i < ps1->size; i++)
	{
		if (ps1->a[i] == x)
		{
			return i;
		}
	}
	return -1;
}

修改i指定下标数字

(SeqList.c)

//修改指定下标数字
void SeqListModify(SeqList* ps1, size_t pos, SLDataType x)
{
	assert(ps1);
	assert(pos < ps1->size);
	ps1->a[pos] = x;
}

测试

写完全部的代码我们随便写一些玩一下(狗头)

int main()
{
	SeqList s;
	SeqListInit(&s);
	SeqListPushFront(&s, 4);
	SeqListPushFront(&s, 3);
	SeqListPushFront(&s, 2);
	SeqListPushFront(&s, 1);
	SeqListPrint(&s);
	SeqListPushBack(&s, 4);
	SeqListPushBack(&s, 3);
	SeqListPushBack(&s, 2);
	SeqListPushBack(&s, 1);
	//1 2 3 4 4 3 2 1 
	SeqListInsert(&s, 4, 5);
	SeqListPrint(&s);
	//1 2 3 4 5 4 3 2 1
	SeqListErase(&s, 4);
	SeqListPrint(&s);

	SeqListFind(&s, 2);
	SeqListModify(&s, 0, 8);
	SeqListPrint(&s);


	SeqListDestroy(&s);

}

代码运行结果如图

完整代码

SeqList.h

#pragma once

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
//创建顺序表
typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* a;//动态开辟数组
	int size;//存储顺序表中有效数据的个数
	int capacity;//存储空间个数-->记录最大容量
}SeqList;

//初始化顺序表
void SeqListInit(SeqList* ps1);
//检测是否需要扩容
void SeqListCheckCapacity(SeqList* ps1);
//打印顺序表
void SeqListPrint(SeqList* ps1);
//销毁顺序表
void SeqListDestroy(SeqList* ps1);
//尾插
void SeqListPushBack(SeqList* ps1, SLDataType x);
//尾删
void SeqListPopBack(SeqList* ps1);
//头插
void SeqListPushFront(SeqList* ps1, SLDataType x);
//头删
void SeqListPopFront(SeqList* ps1);
//在pos位置插入x
void SeqListInsert(SeqList* ps1, size_t pos, SLDataType x);
//删除pos位置的数据
void SeqListErase(SeqList* ps1, size_t pos);
//查找指定数字
int SeqListFind(SeqList* ps1, SLDataType x);
//修改指定下标数字
void SeqListModify(SeqList* ps1, size_t pos, SLDataType x);

test.c

#define _CRT_SECURE_NO_WARNNG 1
#include "SeqList.h"


int main()
{
	SeqList s;
	SeqListInit(&s);
	SeqListPushFront(&s, 4);
	SeqListPushFront(&s, 3);
	SeqListPushFront(&s, 2);
	SeqListPushFront(&s, 1);
	SeqListPrint(&s);
	SeqListPushBack(&s, 4);
	SeqListPushBack(&s, 3);
	SeqListPushBack(&s, 2);
	SeqListPushBack(&s, 1);
	//1 2 3 4 4 3 2 1 
	SeqListInsert(&s, 4, 5);
	SeqListPrint(&s);
	//1 2 3 4 5 4 3 2 1
	SeqListErase(&s, 4);
	SeqListPrint(&s);

	SeqListFind(&s, 2);
	SeqListModify(&s, 0, 8);
	SeqListPrint(&s);


	SeqListDestroy(&s);

}

SeqList.c

#define _CRT_SECURE_NO_WARNNG 1
#include "SeqList.h"

//初始化顺序表
void SeqListInit(SeqList* ps1)
{
	assert(ps1);
	ps1->a = NULL;
	ps1->size = 0;
	ps1->capacity = 0;
}

//检测是否需要扩容
void SeqListCheckCapacity(SeqList* ps1)
{
	assert(ps1);
	//如果满了就需要扩容
	if (ps1->size == ps1->capacity)
	{
		size_t newCapacity = ps1->capacity == 0 ? 4 : ps1->capacity * 2;
		SLDataType* tmp = realloc(ps1->a, sizeof(SLDataType) * newCapacity);
		if (tmp == NULL)
		{
			printf("realloc fail
");
			exit(-1);
		}
		else
		{
			ps1->a = tmp;
			ps1->capacity = (int)newCapacity;
		}
	}
}

//打印顺序表
void SeqListPrint(SeqList* ps1)
{
	assert(ps1);
	for (int i = 0; i < ps1->size; i++)
	{
		printf("%d ", ps1->a[i]);
	}
	printf("
");
}

//销毁顺序表
void SeqListDestroy(SeqList* ps1)
{
	assert(ps1);
	free(ps1->a);
	ps1->a = NULL;
	ps1->capacity = ps1->size = 0;
}

//尾插
void SeqListPushBack(SeqList* ps1, SLDataType x)
{
	assert(ps1);
	//法1
	//先检查容量
	SeqListCheckCapacity(ps1);
	ps1->a[ps1->size] = x;
	ps1->size++;
	//法2(特殊的下标插入)
	//SeqListInsert(ps1, ps1->size, x);
}

//尾删
void SeqListPopBack(SeqList* ps1)
{
	assert(ps1);
	//法1
	if (ps1->size > 0)
	{
		ps1->size--;
	}
	//法2(特殊的下标删除)
	//SeqListErase(ps1, ps1->size - 1);
}

//头插
void SeqListPushFront(SeqList* ps1, SLDataType x)
{
	assert(ps1);
	//法1
	//先检查容量
	SeqListCheckCapacity(ps1);
	int end = ps1->size - 1;
	while (end >= 0)
	{
		ps1->a[end + 1] = ps1->a[end];
		end--;
	}
	ps1->a[0] = x;
	ps1->size++;
	//法2(特殊的下标插入)
	//SeqListInsert(ps1, 0, x);

}

//头删
void SeqListPopFront(SeqList* ps1)
{
	assert(ps1);
	//法1
	if (ps1->size > 0)
	{
		int begin = 1;
		while (ps1->size > begin)
		{
			ps1->a[begin - 1] = ps1->a[begin];
			begin++;
		}
	}
	//法2(特殊的下标删除)
	//SeqListErase(ps1, 0);
}

//在pos位置插入x
void SeqListInsert(SeqList* ps1, size_t pos, SLDataType x)
{
	assert(ps1);
	//检查pos是否越界?
	// 暴力检查assert
	assert(ps1->size >= pos && ps1);
	//检查容量
	SeqListCheckCapacity(ps1);
	//插入数据
	int end = ps1->size - 1;
	while (end >= (int)pos)
	{
		ps1->a[end + 1] = ps1->a[end];
		end--;
	}
	ps1->a[pos] = x;
	ps1->size++;
}

//删除pos位置的数据
void SeqListErase(SeqList* ps1, size_t pos)
{
	assert(ps1);
	assert(ps1->size > pos && pos);
	size_t begin = pos + 1;
	while (begin < ps1->size)
	{
		ps1->a[begin - 1] = ps1->a[begin];
		begin++;
	}
	ps1->size--;
}

//查找指定数字
int SeqListFind(SeqList* ps1, SLDataType x)
{
	assert(ps1);
	for (int i = 0; i < ps1->size; i++)
	{
		if (ps1->a[i] == x)
		{
			return i;
		}
	}
	return -1;
}

//修改指定下标数字
void SeqListModify(SeqList* ps1, size_t pos, SLDataType x)
{
	assert(ps1);
	assert(pos < ps1->size);
	ps1->a[pos] = x;
}
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。