《从 0 到 1 理清C 语言顺序表:底层原理 + 操作实现 》

前言:

本文指在总结C语言顺序表实现的底层原理及表层操作实现,对初学C语言顺序表的人能有个深入的了解,希望能对你有帮助。


 

目录

前言:

顺序表与数据结构及线性表 

数据结构

线性表 

顺序表

底层原理

分类

优缺点

顺序表操作实现

定义

空间开辟

初始化:

销毁:

头插:

尾差:

指定插入:

尾删;

头删:

指定删:

查找数据:

修改数据:


一、顺序表与数据结构及线性表 

(一)数据结构

顺序表顾名思义,你可以把它看作是一个表格。顺序表是数据结构的一种,因此可以说是刚开始入门数据结构,那么想了解顺序表就必须对数据结构的定义有个认知了解。那么数据结构是什么呢?在生活中你可以有这样的烦恼,在书房里,一本本书散落在房间的各个角落,零零散散,想找一本书需要花费较多的时间。为了提升我们找书的效率我们会将书归纳分类整理到一个书架上,这样在找书的时候只需知道自己所找的书在哪一类就行了。因此可以说书架就是一个数据结构。

用专业点的说法:数据结构就是计算机存储和组织数据的方式。从名字就能看出数据结构有两部份组成,一是数据,其次是结构,将数据组织和存储合适的结构上叫数据结构。

(二)线性表 

本文提到的顺序表其实是线性表的一种,线性表是指具有相同特性的数据结构的集合。

两大特性:内存中存储的物理结构不一定连续;逻辑结构一定连续。

线性表有很多种,包括:顺序表、链表、栈、队列、字符串……

(三)顺序表

1.底层原理

顺序表的底层原理其实就是一个数组,只不过顺序表在数组的基础上增加了许多现成的方法,开箱即用,能直接对数组进行增删查改等操作。数组可分为定长数组(初始化的时候给定数组一个初始值大小)和动态柔性数组(数组的大小可改变)。那么基于数组的顺序表也可分为静态顺序表和动态顺序表。

2.分类

顺序表:动态顺序表、静态顺序表。

3.优缺点

静态顺序表:在知道具体的数据数量上,使用静态顺序表,比如有十个字符数据,就给十个字符数组的空间大小。

动态顺序表:在不清楚数据具体容量且数据量动态变化的就使用动态顺序表,可随数据量的大小而变化。

对比:在数据量不明的时候,相较静态顺序表,动态顺序表则显得更具优势,动态顺序表可随数据量的增加而扩充空间,但是静态顺序表如果空间一开始给大了可能造成浪费,给小了可能又会不够用。

二、顺序表操作实现

 定义

静态顺序表的定义:

struct Sequlist
{
    int arr[100];   
    int size;
};
//底层是一个定长的数组

动态顺序表定义:

struct Seqlist
{
    int* arr;
    int size;       //有效存储数据个数
    int capacity;   //空间容量大小
};
//给一个指针,后面动态开辟空间进行扩容

想到顺序表,我们习惯推荐使用动态顺序表,因为相比之下,更有好处。

空间开辟

需要使用到动态空间开辟函数(malloc、calloc、realloc),为了动态扩容,这里使用realloc函数。

struct Seqlist ps;  //创建一个顺序表
void Secheckcapacity()
{
    if(ps.szie==ps.capacity)
    {    //数据容量两倍两倍地扩容(符合数学定律)
    int newcapacity = ps.capacity==0 ? 4 : 2 * ps.capacity;
    (int *)tem = (int *)realloc(ps.arr,newcapacity * sizeof(int));
    if(tem==NULL)
    {
        perror("realloc:");
        exit(1);
     }
    //扩容成功
    PS.arr = tem;
    ps.capacity = newcapacity;
    }
}

根据数据容量动态开辟空间是动态顺序表的核心要点,了解了这里之后,后面的一系列基于顺序表的操作就很容易实现。

其中方法包括:

顺序表初始化和销毁:

增加插入数据:尾差、头插、指定插入

删除数据:尾删、头删、指定删除

查找数据和修改数据:

具体实现:

初始化:

void SLinit(SL* ps)
{
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

销毁:

void SLdestory(SL* ps)
{
	if (ps->arr)
	{
		free(ps->arr);
		ps->arr = NULL;
	}
	ps->size = ps->capacity = 0;
}

头插:

void SLpushfront(SL* ps, SLdatatype x)
{
	assert(ps);
	SLcheckspace(ps);
	//插入数据
	for (int i = ps->size-1; i >=0; i--)
	{
		ps->arr[i + 1] = ps->arr[i];
	}
	ps->arr[0] = x;
	ps->size++;

}

尾差:

void SLpushback(SL* ps,SLdatatype x)
{
	assert(ps);
	//插入前先检查是否有足够空间
	if (ps->size == ps->capacity)
	{	 //会报错,capacity初始值为0,(可以在顺序表初始化时给其空间,但同时要开辟相应的空间)
		 //ps->arr = (SLdatatype*)realloc(ps->arr, ps->capacity * 2 * sizeof(SLdatatype));
		int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLdatatype* tem = realloc(ps->arr, newcapacity * sizeof(SLdatatype));
		if (tem == NULL)
		{
			perror("perror:");
			exit(1);
		}
		//空间开辟成功
		ps->arr = tem;
		ps->capacity = newcapacity;
	}
	//插入数据
	ps->arr[ps->size] = x;
	ps->size++;
}

指定插入:

void SLinsect(SL* ps, int pos,SLdatatype x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	SLcheckspace(ps);
	for (int i = ps->size - 1; i >=pos ; i--)
	{
		ps->arr[i + 1] = ps->arr[i];
	}
	ps->arr[pos] = x;
	ps->size++;
}

尾删;

void SLdelback(SL* ps)
{
	assert(ps);
	assert(ps->size);//确保有数据可删
	ps->size--; //不影响其他方法,可以直接将size--;
	//另一种方法(可行,但没必要)
	//ps->arr[ps->size - 1] = -1;
	//ps->size-
}

头删:

void SLdelfront(SL* ps)
{
	assert(ps);
	assert(ps -> size);
	
	for (int i = 0; i < ps->size-1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	--ps->size;
}

指定删:

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

查找数据:

int SLcheck(SL sl, SLdatatype x)
{
	for (int i = 0; i < sl.size; i++)
	{
		if (sl.arr[i] == x)
		{
			printf("找到了!\n");
			return i;
		}
	}
	printf("没找到\n");
	return -1;
}

修改数据:

void SLmodify(SL* ps, int pos, SLdatatype x)
{
	assert(ps);
	ps->arr[pos] = x;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值