C语言---顺序表(详解)---数据结构

我们直接切入主题

1.首先这次写的顺序表的动态的,因为静态的弊端较多。

2.顺序表的功能函数有:初始化 丶申请动态内存 顺序表的头部,尾部的插入和删除 丶在特定位置的插入和删除 丶打印顺序表 丶释放动态内存

需要用到的头文件

我们先给 类型 重命名

原因是:以后还需要用到顺序表时,插入的不一定是你当前使用的类型,如果要改还需要一个个改,非常麻烦,为了以后方便,我们需要改类型时,直接给 类型重命名 这里改,就可以了,更加节省时间。

创建一个结构体里面包含

1指向动态开辟数组的指针。*a

2记录有效数据的个数 size

3容量的大小 capacity

前置准备写好了,可以开始实现各个函数功能了。 

1 初始化

初始化较为简单 指针置为空,size置为0,需要注意的是容量大小要置为4(或者其他大小)至于为什么,后面讲)(这里不讲是因为和后面函数对应)

2. 内存扩容

这里的newcapacity是给capacity扩容 

int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;

这里的ps->capacity*2跟上面的capacity置为4相对应,如果capacity置为0,那么0*2还是0,无法扩容,导致这个顺序表大小只有4,为什么只有4,原因在ps->capacity == 0 ? 4

if语句是判断realloc会不会申请内存失败(一般是不会的,但是为了安全性还是必须写的)

最后我们直接把 tmp 接收 申请好的内存数组赋给a

再把newcapacity扩容好的值赋给capacity

这里会有点难理解 需要读者慢慢消化

3.顺序表头部插入

这里需要注意 头部插入和尾部插入的顺序可以颠倒

但是在第一个插入的函数 必须直接让扩容函数直接执行,让ps->a申请内存,不然ps->a为空,无法进行插入 会直接报错

 代码思路:

让end放在有效数据的前一个数字(简单来说就是让end放在顺序表最后一个位置,向前走,分别想换他们的位置

while end>=0是判断到 数组开头的数据移动后一位,为要插入的数据腾出空间

ps->a[end+1]=ps->a[end]

把最后一个数据移动到size这个为空的有效位置

移动完后 让end往前走 (++是往后走 --是往前走

循环结束后 所有的数据都往后移动了一个位置

再把 x (就是你想插入的数据)插入到第一个位置 a[0]就是数组的第一个位置

再让size++ 有效数据有多了一个

4.顺序表的尾部插入

这是第二次插入 不能让扩容直接进入,需要判断有效数据是否达到了容量大小

如果达到就扩容 ,没达到就无需扩容 。

尾部插入比较简单

因为size本身就指向有效数据的后一位,我们直接在size这里添加,再让size往后移一下,就完成了尾部插入。

 5.顺序表的头部删除

int end =1 让end放在数组的第二个位置 (数组0是第一个位置 所以1是第二个位置)

while (end < ps->size)第二位置开始 一直到最后的有效数据

先把数组第二的位置覆盖到数组第一个位置 然后就删除了 

但是数组第二个位置就为空了 让第三个数据覆盖上来 

但是数组第三个位置就为空了 让......依次类推

++end就是让end往后走 持续交换

ps->size-- 有效数据少一个 所以size要--

6.顺序表的尾部删除

因为是尾部删除 而size也是指向有效个数,直接让size--就等于删除了最后一个数据,就是尾部删除了

7.在特定位置插入 

只要是插入数据 我们都要进行判断容量的大小是否满了

让end放在size的前一位

把最后一个数据往后移动

让end--(往前移动)

while (end < ps->size)直到pos这个位置的数据也往后移动一位

循环结束后pos后面的数据 包括pos这个位置的数据都往后移动了一位,pos这个位置是空数据,为插入的数据腾出了空间 我们直接插入就可以了

(注意 pos 是数组小标位置 不是数据为几  例如 0 ,1就是数组的第一个和第二个,而不是数字0,1)

size++ 有效数据插入一个 就++

8.在特定位置删除数据

这个函数原理跟头部删除差不多 

它是在pos的后一位数据的位置 往前覆盖 ,而头部删除是在头部数据的后一位往前覆盖

9.打印顺序表 

这里直接让i从0开始一直到size这里的有效数据都打印一边就可以了。

 10.释放申请的动态内存

我们把指针释放 再置为空

然后把有效数据和容量大小都置为0

 所有函数功能就实现了

下面是代码(需要可以自取)

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

//以后要用到顺序表不一定是用到 int 类型 如果要该类型非常麻烦需要一个个改
//给类型重命名 以后需要用到哪种类型 直接在这里改就可以了 更加方便
typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* a;//指向动态开辟数组的指针
	int size;//有效的数据个数
	int capacity;//容量的大小
}SeqList;

//初始化
void SeqListInit(SeqList* ps)
{
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 4;
}

void Expand(SeqList* ps)
{
	int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
	SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * sizeof(SLDataType));  
	if (tmp == NULL)
	{
		printf("realloc fail");
		exit(-1);
	}
	else
	{
		ps->a =tmp;
		ps->capacity = newcapacity;
	}
}


//顺序表的头部插入元素
void SeqListPushBack(SeqList* ps, SLDataType x)
{
	//第一次进行插入 的时候 不管是头 尾 插入 都必须直接进入扩容阶段 
		Expand(ps);
		int end = ps->size - 1;
		while (end >= 0)
		{
			ps->a[end + 1] = ps->a[end];
			--end;
		}
		ps->a[0] = x;
		ps->size++;
}

void SeqListPushFront(SeqList* ps, SLDataType x)
{
	if (ps->size == ps->capacity)
	{
		Expand(ps);
	}
	ps->a[ps->size] = x;
	ps->size++;
}


void SeqListPrint(SeqList* ps)
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->a[i]);
	}
}

void SeqListDestory(SeqList* ps)
{
	free(ps->a);
	ps->a = NULL;
	ps->size = ps->capacity = 0;
}

void SeqListPopBack(SeqList* ps)
{
	int end = 1;
	while (end < ps->size)
	{
		ps->a[end - 1] = ps->a[end];
		end++;
	}
	ps->size--;
}

void SeqListPopFront(SeqList* ps)
{
	assert(ps->size > 0);

	ps->size--;
}

int SeqListFind(SeqList* ps, SLDataType x)
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
	}
	return;
}

//pos不是0这个数字 在现在的元素里是没有0这个数的 0表示的是数组下标
void SeqListInsert(SeqList* ps, int pos, SLDataType x)
{
	if (ps->size == ps->capacity)
	{
		Expand(ps);
	}
	int end = ps->size-1;
	while (end >= pos)
	{
		ps->a[end +1] = ps->a[end];
		--end;
	}
	ps->a[pos] = x;
	ps->size++;
}

void SeqListErase(SeqList* ps, int pos)
{
	int end = pos + 1;
	while (end < ps->size)
	{
		ps->a[end - 1] = ps->a[end];
		++end;
	}
	ps->size--;
}

void Inteliode()
{
	SeqList st;
	//void SeqListInit(SeqList* ps);
	SeqListInit(&st);
	//void SeqListDestory(SeqList* ps);

	//void SeqListPrint(SeqList* ps);
	
	//void SeqListPushBack(SeqList* ps, SLDateType x);
	SeqListPushBack(&st, 5);
	SeqListPushBack(&st, 4);
	SeqListPushBack(&st, 3);
	SeqListPushBack(&st, 2);
	SeqListPushBack(&st, 1);
	//void SeqListPushFront(SeqList* ps, SLDateType x);
	SeqListPushFront(&st, 6);
	SeqListPushFront(&st, 7);
	SeqListPushFront(&st, 8);
	SeqListPushFront(&st, 9);
	SeqListPushFront(&st, 10);
	//void SeqListPopFront(SeqList* ps);
	SeqListPopFront(&st);
	SeqListPopFront(&st);
	SeqListPopFront(&st);
	//void SeqListPopBack(SeqList* ps);
	SeqListPopBack(&st);
	SeqListPopBack(&st);
	SeqListPopBack(&st);
	 顺序表查找
	//int SeqListFind(SeqList* ps, SLDateType x);
	int pos=SeqListFind(&st, 4);
	SeqListInsert(&st, 0, 50);
	这里的5不是说数字5 而是数组下标
	SeqListErase(&st, 0);
	 顺序表在pos位置插入x
	//void SeqListInsert(SeqList* ps, size_t pos, SLDateType x);
	 顺序表删除pos位置的值
	//void SeqListErase(SeqList* ps, size_t pos);
	SeqListPrint(&st);
	SeqListDestory(&st);
}


int main()
{
	Inteliode();

	return 0;
}

 有问题可以发表评论。

  • 4
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值