线性表—顺序表实现

本文详细介绍了如何在C语言中使用结构体和动态数组实现顺序表,包括初始化、销毁、扩容、打印、数据插入和删除操作,以及查找功能的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章目录

线性表介绍

顺序表介绍

创建顺序表

初始化

销毁

扩容

打印

增加数据

尾插

头插

指定下标插入

删除数据

尾删

头删

指定下标删除

查找

整体代码

SeqList.h

SeqList.c


线性表介绍

     线性表是n个具有相同特性的数据元素的有限序列。线性表在逻辑结构上一定是连续的,但物理结构不一定连续。

顺序表介绍

     顺序表是在计算机内存中以数组的形式保存的线性表。

创建顺序表

在创建顺序表之前要先创建3个项目,为什么要创建多个项目呢?这是为了方便我们管理。

     test.c用于测试函数。

     SeqList.c函数实现。

     SeqList.h函数声明和顺序表的定义。

     顺序表需要有指向动态数组指针有效数据个数容量

     这就要用结构体来定义了:

typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* arr;//指向动态数组的指针
	int size;//有效数据个数
	int capacity;//容量

}SL;

    typedef函数是用来重命名的。

   为了方便后续修改顺序表数据类型,我们可以用 typedef重新给数据类型命名为 SLDataType。

    同理在这里把结构体类型重命名为SL。

初始化

     初始化就是把arr置为空指针,其余为0。

//初始化
void SLInit(SL* ps)
{
    assert(ps);//检查是否为空指针
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}

     assert是判断传过来的参数是否为NULL,如果是则退出,否则继续执行。在后面的函数中都会涉及到它。

销毁

     为什么要销毁呢?顺序表是动态开辟在堆区的,如果不销毁会造成内存泄漏。销毁用到的是free函数,把其余置为0即可。

//销毁
void SLDestroy(SL* ps)
{
	assert(ps);
	if (ps->arr)//判断arr是否为NULL
	{
		free(ps->arr);
	}
	ps->arr = NULL;//防止出现野指针
	ps->capacity = ps->size = 0;
}

扩容

     先检查是否要开辟。在确定开辟多大容量后(我写的是上一次容量的1倍),用realloc函数开辟一块空间,开辟完后要检查一下是否开辟失败。然后再把它的值赋给arr。

//扩容
void SLCheckCapacity(SL* ps)
{
    assert(ps);
	if (ps->capacity == ps->size)//判断是否要扩容
	{
		ps->capacity = ps->capacity == 0 ? ps->capacity = 2 : ps->capacity * 2;//扩后容量大小
		SLDataType* new = (SLDataType*)realloc(ps->arr, ps->capacity * sizeof(SLDataType));//创建一片空间
		if (new == NULL)//判断创建是否失败
		{
			perror("realloc:");
			exit(1);
		}
		ps->arr = new;
	}
}

打印

     遍历一遍即可。

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

增加数据

     在增加数据前要检查容量是否满了。增加完数据后,size要加一。

尾插

     在最后的位置插入数据即可。

//尾插
void SLpushBack(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	ps->arr[ps->size++] = x;
}

     演示:

88fb751e0f91467ab100c1e7ea743b51.png

头插

     把原数据依次向后移一位,挪动数据的时候应从后向前依次挪动,若从前向后挪动,会导致后一个数据被覆盖。然后在首位置插入数据。

//头插
void SLpushFront(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);

	for (int i = ps->size; i > 0; i--)//把原数据向后移一位
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[0] = x;//插入数据
	ps->size++;//有效数据个数加一
}

     演示:

916e699cdb724fcca8eb92b5adcb29ef.png

指定下标插入

     要检查下标是否合理,然后把下标之后的数据依次向后移一位,挪动数据的时候要从后向前依次挪动。然后在把数据插入。

//指定下标插入数据
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);//检查下标是否合理
	SLCheckCapacity(ps);
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	ps->size++;
}

     演示:

6d7012b4d3fc451f8a89f69275881f03.png

删除数据

      删除数据前要判断顺序表中是否有数据。在删除完数据后,size要减一。

尾删

    size减一即可。

//尾删
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);//判断顺序表中是否有数据
	ps->size--;
}

     演示:

8e1898babeaa41b3b5f1d37a60df2b4b.png

头删

     把所有数据依次向前移一位即可,挪动数据的时候应从前向后依次挪动,若从后向前挪动,会导致后一个数据被覆盖。

//头删
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);

	for (int i = 1; i < ps->size; i++)//所有数据向前移一位
	{
		ps->arr[i - 1] = ps->arr[i];
	}
	ps->size--;//有效数据减一
}

     演示:

57989b46e986464ca910ecde3d4c1557.png

指定下标删除

     要检查下标是否合理,再把下标之后的数据依次向前移一位,挪动数据的时候应从前向后依次挪动。

void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	assert(ps->size);
	for (int i = pos; i < ps->size - 1; i++)//把下标pos之后的数据向前移
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;

}

     演示:

0686f0c104ce48c29d02ef5652aec318.png

查找

     在遍历一遍时判断有无相等若有返回下标,否则返回-1。

//查找
int SLFind(SL* ps, SLDataType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
		{
			return i;
		}
	}
	return -1;
}

     演示:

f4f3dfe218a04631ad5aad255ad7df4e.png

整体代码

SeqList.h

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>


typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* arr;
	int size;
	int capacity;

}SL;

//初始化
void SLInit(SL* ps);

//扩容
void SLCheckCapacity(SL* ps);

//打印
void SLPrint(SL* ps);

//尾插
void SLpushBack(SL* ps, SLDataType x);

//头插
void SLpushFront(SL* ps, SLDataType x);

//尾删
void SLPopBack(SL* ps);

//头删
void SLPopFront(SL* ps);

//指定下标插入数据
void SLInsert(SL* ps, int pos, SLDataType x);

//指定下标删除数据
void SLErase(SL* ps, int pos);

//查找
int SLFind(SL* ps, SLDataType x);

//销毁
void SLDestroy(SL* ps);

SeqList.c

#include "SeqList.h"

//初始化
void SLInit(SL* ps)
{
    assert(ps);
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}

//扩容
void SLCheckCapacity(SL* ps)
{
    assert(ps);
	if (ps->capacity == ps->size)
	{
		ps->capacity = ps->capacity == 0 ? ps->capacity = 2 : ps->capacity * 2;
		SLDataType* new = (SLDataType*)realloc(ps->arr, ps->capacity * sizeof(SLDataType));
		if (new == NULL)
		{
			perror("realloc:");
			return;
		}
		ps->arr = new;
	}
}

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

//尾插
void SLpushBack(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	ps->arr[ps->size++] = x;
}

//头插
void SLpushFront(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);

	for (int i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[0] = x;
	ps->size++;

}

//尾删
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);
	ps->size--;
}

//头删
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);

	for (int i = 1; i < ps->size; i++)
	{
		ps->arr[i - 1] = ps->arr[i];
	}
	ps->size--;
}

//指定下标插入数据
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	SLCheckCapacity(ps);
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	ps->size++;
}

//指定下标删除数据
void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	assert(ps->size);
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;

}

//查找
int SLFind(SL* ps, SLDataType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
		{
			return i;
		}
	}
	return -1;
}

//销毁
void SLDestroy(SL* ps)
{
	assert(ps);
	if (ps->arr)
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}

     


     好了讲到这儿就差不多讲完了,希望你能有所收获。如果存在错误地方请及时指出,如果还有什么不懂的地方可以私信我,如果觉得不错那就点点赞吧!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值