数据结构——线性表

数据结构——线性表

一不小心拖了好久的博客没写了…今天给大家带来数据结构中第一个基本的数据结构线性表

1.定义

线性表这个名字听起来很高大上,其实它的本质就是数组,线性表要求要用一块连续的空间来存放数据,正好数组满足这样的特性,所以接下我们对线性表做的任何操作其实都是对数组进行操作。
在这里插入图片描述
线性表的基本操作有。但在这之前,我们得先有一个线性表才行。

2.定义线性表结构体和初始化线性表

2.1静态线性表和动态线性表

我们之前说过,线性表的本质就是一个数组,其实直接定义一个数组,就是一个线性表,但我们通常会定义一个变量来记录线性表中存放了几个数据,这个数据我们称为有效数据
在这里插入图片描述

但这样我们会发现非常的不方便,在上图中我定义了data这个数组最多只能存放10个数据,只能少不能多,一旦数据过多,这种静态的线性表弊端很大。
那有没有解决方法呢?当然有,还记得动态开辟内存吗?malloc函数。我们把data数组用malloc动态开辟,只要存放数据个数超过上限,就自动再开辟空间,解决了静态线性表的问题。
在这里插入图片描述

2.2 初始化线性表

首先进行之前,得有一个线性表。
首先在头文件里进行声明:
在这里插入图片描述
然后进行实现:

在这里插入图片描述这段代码干了啥呢?
在这里插入图片描述

3.增(插入数据)

3.1尾插

初始化线性表之后,我们就可以对线性表进行一些操作了。我们首先来看第一种插入方法——尾插
顾名思义尾插就是在尾部插入数据
现在我想把1,2,3,4插入到线性表中:
在这里插入图片描述
我们发现每次插入的位置就是size的下标,那么就好办了。
在这里插入图片描述
但是别高兴的太早,我们还没考虑到万一线性表满了呢?如果满了,我们就需要对线性表进行扩容,然后对剩下的数据进行插入。

3.1.1检查扩容

比如现在我的线性表已经满了:
在这里插入图片描述
现在我们要扩容,怎么办呢?大家还记得realloc吗?
在这里插入图片描述
这段代码又干嘛了呢?
在这里插入图片描述
realloc申请空间有两种情况,这里只介绍一种。

3.1.2打印线性表中元素

打印线性表中元素就和打印数组元素一样:
在这里插入图片描述
我们测试一下我们的尾插成功没有:
在这里插入图片描述在这里插入图片描述

3.2头插

头插就是在头部插入数据,稍微比尾插麻烦点:
在这里插入图片描述它麻烦的地方在于:第一个位置之前就有数据,如果想要头插,就要全体往后移,让出这个一位
我们有两种移法:从前往后移从后往前移
在这里插入图片描述
我们发现从前往后移,会覆盖数据,如果打印出来会全是线性表第一个元素。这显然不是我们想要的效果。
在这里插入图片描述
我们发现这样才是正确的移法,既然知道方法之后,写代码就轻而易举了:
在这里插入图片描述
我们来测试一下:
在这里插入图片描述在这里插入图片描述

3.3一般插入

一般插入和头插的逻辑非常像,头插是要把一位留出来,而一般插入是需要把那个要插入的位置留出来
比如现在我想把7插入到3号位置上:
在这里插入图片描述就和头插的逻辑一样,从后往前移到pos位置停止
在这里插入图片描述
在这里插入图片描述

测试一下:
在这里插入图片描述在这里插入图片描述

3.3.1合并情况

我们发现,头插和尾插是一般插入的特殊情况,那么头插和尾插应该都可以用一般插入表示:
在这里插入图片描述在这里插入图片描述测试一下:
在这里插入图片描述

4.删(删除)

4.1 尾删

线性表的删除和插入一样都有两种,我们先来来看一种比较简单的尾删
大家在这里要有一个概念删除数据不一定要给它弄没,只要不遍历这个元素就行了,这样做会极大简化我们的工作量。
在这里插入图片描述

在这里插入图片描述
测试一下:
在这里插入图片描述
在这里插入图片描述

4.2头删

头删相对来说要复杂一些,原理就是后面的数据依次将前面的数据覆盖
但这里又会有两种方式从前往后从后往前

4.2.1从后往前

在这里插入图片描述

我们会发现所有的数据都会覆盖成最后一个数据,所以这是错误移法。

4.2.2从前往后

在这里插入图片描述这里探索出了正确移法,但又有一个问题:

4.2.2.1结束条件

4.2.2.1.1start=0

我们先来一种,定义一个start,让它指向线性表的第一个元素
在这里插入图片描述start+1覆盖start,来达到覆盖前面元素的效果。但有个问题,什么时候结束
在这里插入图片描述我们发现start+1走到size对应位置的前一位故start+1 < size,satrt < size -1

在这里插入图片描述

测试一下:
在这里插入图片描述
在这里插入图片描述

4.2.2.1.2start=1

我们还有第二种,start指向第二个元素
在这里插入图片描述
在这里插入图片描述我们发现start走到size对应位置的前一位故start < size

在这里插入图片描述

测试一下:
在这里插入图片描述在这里插入图片描述

4.3一般删除

一般的删除和头删的思路很相似,只不过是把要删的元素从第一个改为你想要删的位置的元素。和头删的思路,我这里
start=0演示
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

在这里插入图片描述

4.3.1合并情况

我们发现,头删和尾删是一般删除的特殊情况,那么头删和尾删应该都可以用一般删除表示:
在这里插入图片描述

5.查(寻找值)

前面算是线性表的难点了,到这基本上都是一些轻松的活了。
查就是遍历一遍线性表,若找到返回对应的下标,若没有返回-1
在这里插入图片描述

6.改

直接对位置进行操作即可:
在这里插入图片描述

7.销毁线性表

直接释放掉L->data的空间,然后L->data=NULL,L->size=0, L->capacity=0
在这里插入图片描述

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

//定义线性表结构体

//静态
//typedef struct SList 
//{
//	int data[10];
//	int size;
//}SList;

//动态
typedef int SLData; //将数据类型暂时定为int,如果数据类型有变,直接改即可
typedef struct SList
{
	SLData* data; //动态数组
	int capacity; //目前线性表所能容纳的最大数据个数
	int size; //有效数据个数
}SList;

//初始化线性表
void InitSList(SList* L);

//尾插
void TailInsert(SList* L,SLData X);

//打印线性表中元素
void PrintList(SList* L);

//头插
void ForntInsert(SList* L, SLData X);

//一般插入
void InsertList(SList* L, int pos, SLData X);

//尾删
void TailErase(SList* L);

//头删1
void FontErase_1(SList* L);

//头删2
void FontErase_2(SList* L);

//一般删除
void Erase(SList* L,int pos);

//查找
int Find(SList* L, int number);

//修改
void Modify(SList* L, int pos, int X);

//销魂线性表
void DestoryList(SList* L);
SList.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"head.h"

//初始化线性表
void InitSList(SList* L) //传地址
{
	assert(L != NULL);
	L->data = (SLData*)malloc(sizeof(SLData)*4); //先开辟4个SLData数据的空间

	//判断是否成功
	if (L->data == NULL)
	{
		perror("malloc fail");
	}
	L->capacity = 4; //目前最大容量为4

	L->size = 0; //目前没有存放数据,有效数据为0
}


//检查容量
void CheckCapacity(SList* L)
{
	//检查是否达到上限
	if (L->size == L->capacity)
	{
		SLData* temp = (SLData*)realloc(L->data,sizeof(SLData)*2* L->capacity);//开辟两倍大的空间
		if (temp == NULL)
		{
			perror("realloc fail");
		}
		L->data = temp;//开辟成功之后才交给原来的空间
		L->capacity *= 2;
	}
}
//尾插
void TailInsert(SList* L,SLData X)
{
	assert(L != NULL);
	CheckCapacity(L);
	/*L->data[L->size++] = X;*/

	InsertList(L, L->size, X);
}

//打印线性表中元素
void PrintList(SList* L)
{
	assert(L != NULL);
	for (int i = 0; i < L->size; i++)
	{
		printf("%d ", L->data[i]);
	}
	printf("\n");
}

//头插
void ForntInsert(SList* L,SLData X)
{
	assert(L != NULL);
	CheckCapacity(L);//检查容量

	从后往前移
	//int end = L->size - 1;
	//while (end >= 0)
	//{
	//	L->data[end + 1] = L->data[end];
	//	end--;
	//}

	插入数据
	//L->data[0] = X;
	//L->size++;

	InsertList(L, 0, X);
}

//一般插入
void InsertList(SList* L, int pos, SLData X)
{
	assert(L != NULL);
	assert(pos >= 0 && pos <= L->size); //检查插入位置是否合理
	CheckCapacity(L);//检查容量

	//从后往前移
	int end = L->size - 1;
	while (end >= pos)
	{
		L->data[end + 1] = L->data[end];
		end--;
	}

	//插入数据
	L->data[pos] = X;
	L->size++;
}

//尾删
void TailErase(SList* L)
{
	assert(L != NULL);
	/*L->size--;*/
	assert(L->size > 0);
	Erase(L, L->size - 1);
}

//头删1
void FontErase_1(SList* L)
{
	//int start = 0;//指向第一个位置
	//while (start < L->size - 1)
	//{
	//	L->data[start] = L->data[start + 1];
	//	start++;
	//}
	//L->size--;
	assert(L != NULL);
	assert(L ->size > 0);
	Erase(L, 0);
}

//头删2
void FontErase_2(SList* L)
{
	int start = 1;//指向第二个位置
	while (start < L->size)
	{
		L->data[start-1] = L->data[start];
		start++;
	}
	L->size--;
}

//一般删除
void Erase(SList* L,int pos)
{
	assert(L != NULL);
	assert(pos >= 0 && pos <= L->size-1);
	int start = pos;//指向第一个位置
	while (start < L->size - 1)
	{
		L->data[start] = L->data[start + 1];
		start++;
	}
	L->size--;
}

//查找
int Find(SList* L, int number)
{
	assert(L != NULL);
	for (int i = 0; i < L->size; i++)
	{
		if (L->data[i] == number)
		{
			return i;
		}
	}
	return -1;
}

//修改
void Modify(SList* L, int pos, int X)
{
	assert(L != NULL);
	assert(pos >= 0 && pos <= L->size - 1);//判断修改位置是否合理

	L->data[pos] = X;
}

//销毁线性表
void DestoryList(SList* L)
{
	assert(L != NULL);
	free(L->data);
	L->data = NULL;
	L->size = 0;
	L->capacity = 0;
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"head.h"

int main()
{
	//定义一个线性表
	SList L;

	//初始化线性表
	InitSList(&L);

	//尾插
	for (int i = 1; i < 10; i++)
	{
		TailInsert(&L, i);
	}

	//头插
	for (int i = 10; i >= 1; i--)
	{
		ForntInsert(&L, i);
	}

	//一般插入
	InsertList(&L, 6, 89);
	PrintList(&L);

	//尾删
	TailErase(&L);

	//头删
	//FontErase_1(&L);
	FontErase_2(&L);
	PrintList(&L);

	//一般删除
	Erase(&L, 3);

	//打印
	PrintList(&L);

	//查找
	int temp = Find(&L, 4);
	printf("%d\n", temp);

	//修改
	Modify(&L, 2, 100);
	PrintList(&L);

	//销毁线性表
	DestoryList(&L);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值