【数据结构】顺序表的学习

这篇具有很好参考价值的文章主要介绍了【数据结构】顺序表的学习。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:在之前我们学习了C语言的各种各样的语法,因此我们今天开始学习数据结构这一个模块,因此我们就从第一个部分来开始学习"顺序表"。

💖 博主CSDN主页:卫卫卫的个人主页 💞
👉 专栏分类:数据结构 👈
💯代码仓库:卫卫周大胖的学习日记💫
💪关注博主和博主一起学习!一起努力!
【数据结构】顺序表的学习,数据结构的学习,数据结构,顺序表,c语言



顺序表

  1. 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
  2. 顺序表一般可以分为两个部分,静态顺序表(使用定长数组存储元素)和动态顺序表(使用动态开辟的数组存储)。
  3. 静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。

动态顺序表

首先我们创建一个结构体,去实现数据的动态存储。
【数据结构】顺序表的学习,数据结构的学习,数据结构,顺序表,c语言

代码如下:

typedef int SLDataype;//定义整型,方便后面进行数据的更改

typedef struct SeqList //动态顺序表的开辟
{
	SLDataype* a;
	int size; //记录多少个有效数据
	int capacity; //记录空间有多大
}SL;


接下来我们就实现一个个接口来实现顺序表的基本功能

顺序表的初始化

顺序表的初始化十分简单,只需要将开辟的指针置为空指针,有效数据清零,空间容量清零即可。
代码如下:

void SLInit(SL* ps1)//顺序表的初始化
{
	assert(ps1);
	ps1->a = NULL;//将指针置为空指针
	ps1->size = 0;//数据清零
	ps1->capacity = 0;//容量清零
}


顺序表的销毁

同理,顺序表的销毁,只需要判断所开辟的空间是否已经是被释放了,和被置为空指针了,如果不是,就把所开辟的空间释放和数据清零即可。
代码如下:

void SLDestory(SL* ps1)//顺序表的销毁
{
	if (ps1->a != NULL)//判断该指针是否为空指针
	{
		free(ps1->a);//释放该指针所开辟的空间
		ps1->a = NULL;//置为空指针
		ps1->size = 0;//数据清零
		ps1->capacity = 0;//容量清0
	}
}


顺序表的空间容量检查

我们想要实现在所开辟的空间中,增加数据,就不可避免的需要去检查所开辟的空间的容量是否充足,如果不充足,我们就需要去增容,那该增加多少呢?增加太多,会导致空间的浪费,太少又会导致不断的扩容,这是一个双向的问题,因此这也没有什么十分固定的答案,通常来讲,一般增容一倍即可。

代码思路:在检查空间的时候,我们应该考虑传过来的指针是否是空指针,即是否是初始化后的顺序表,但realloc函数是可以对空指针进行扩容的,但是我们为了防止扩容失败,应该开辟一个新的结构体指针来接收这块空间,在开辟成功后重新覆盖回去。

代码实现:

void SLCheckCapacity(SL* ps1)//检查空间
{
	if (ps1->size == ps1->capacity)
	//判断记录的数据个数,与空间容量释放相同,相同的时候即空间满了,需要增容
	{
		int newCapacity = ps1->capacity == 0 ? 4 : ps1->capacity * 2;
		//判断开辟的空间是否是初始化的空间,如果是就让他容量为4,如果不是就开辟当前空间的两倍
		SLDataype* tmp = (SLDataype*)realloc(ps1->a, sizeof(SLDataype) * newCapacity);
		//创建一个新的结构体指针,在他的后面扩容,放在开辟失败后原本的数据也不见了
		//realloc 可以对空指针进行扩容
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		ps1->a = tmp;//将开辟后面的指针传给原本的地址
		ps1->capacity = newCapacity;//更新容量
	}
}

顺序表的打印

void SLPrint(SL* ps1)
{
	for (int i = 0; i < ps1->size; i++)//变量开辟的数据
	{
		printf("%d ", ps1->a[i]);//直接打印
	}
	printf("\n");
}

顺序表的尾增

代码思路:因为前面我们提到了size是有效数据的个数,也是指向的数组的最后一个元素的后一个的位置,因此只需要在此位置赋值即可,然后再让size往后偏移一位。

代码实现:

void SLPushBack(SL* ps1, SLDataype x)//尾增
{
	SLCheckCapacity(ps1);//检查空间容量
	ps1->a[ps1->size] = x;
	//因size指向的是数组最后一个元素的后一个元素,因此只需要直接在此位置赋值即可
	ps1->size++;//size继续指向后一个元素
}

现在我们实现了四个小的接口,忙活了这么久,我们来见一下效果,好歹听个响是吧。
效果图:

void TestSL1()//测试函数
{
	SL s1;//创建动态顺序表
	SLInit(&s1);//初始化顺序表
	SLPushBack(&s1, 2);//尾增数据
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPrint(&s1);//打印数据
	SLPushBack(&s1, 5);
	SLPushBack(&s1, 6);
	SLPrint(&s1);//打印数据
	SLDestory(&s1);//销毁顺序表
}

int main()
{
	TestSL1();
	return 0;
}

【数据结构】顺序表的学习,数据结构的学习,数据结构,顺序表,c语言


顺序表的头增

代码实现思路:我们记录数据的最后一个位置为end,最后一个数据后面的一个数据位置为end+1,让end依次往后覆盖,然后end–直到end到起始位置即停止循环,具体思路如下图:
【数据结构】顺序表的学习,数据结构的学习,数据结构,顺序表,c语言
代码实现:

void SLPushFront(SL* ps1, SLDataype x)//头增
{
	SLCheckCapacity(ps1);//先检查数据

	//挪动数据
	int end = ps1->size - 1;//记录最后一个位置
	while (end >= 0)//end到起始位置时即覆盖完成
	{
		ps1->a[end + 1] = ps1->a[end];//将数据依次往后覆盖
		--end;
	}
	ps1->a[0] = x;//将数据赋值给起始位置就可以实现头增
	ps1->size++;//size++
}

当然了,不能白忙活,我们来测试一下这个函数,来看看效果如何

void TestSL2()
{
	SL s1;//创建动态顺序表
	SLInit(&s1);//初始化顺序表
	SLPushBack(&s1, 2);//尾增数据
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPrint(&s1);//打印尾增的数据
	printf("上面是尾增的数据\n");
	printf("------------------------------\n");
	printf("下面是头增的数据\n");
	SLPushFront(&s1, 20);//头增的数据
	SLPushFront(&s1, 10);
	SLPushFront(&s1, 0);
	SLPushFront(&s1,9);
	SLPrint(&s1);//打印头增的数据
	SLDestory(&s1);//销毁顺序表
}


int main()
{
	//TestSL1();
	TestSL2();
	return 0;
}

【数据结构】顺序表的学习,数据结构的学习,数据结构,顺序表,c语言


顺序表的头删

代码思路:我们记录一个起始位置即数组的第二个元素记录为begin,让他往前面一个数据begin-1覆盖,然后再放入循环中不断覆盖,当运行到size的位置的时候停止循环具体思路如下图:
【数据结构】顺序表的学习,数据结构的学习,数据结构,顺序表,c语言
代码如下:

void SLPopFront(SL* ps1)//头删
{
	assert(ps1->size > 0);//判断传过来是是不是为空数据
	int begin = 1;//将起始位置置为1
	while (begin < ps1->size)//再起始位置等于size时即覆盖完成
	{
		ps1->a[begin - 1] = ps1->a[begin];//后面覆盖前面
		++begin;
	}
	ps1->size--;//size减减
}

当然,我们依然来听个响,听听声音,效果图如下:


void TestSL3()
{
	SL s1;//创建动态顺序表
	SLInit(&s1);//初始化顺序表
	SLPushBack(&s1, 2);//尾增数据
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPushFront(&s1, 20);//头增的数据
	SLPushFront(&s1, 10);
	SLPushFront(&s1, 0);
	SLPushFront(&s1, 9);
	SLPrint(&s1);//打印原本的数据
	printf("上面是原本的数据\n");
	printf("--------------------------------------\n");
	printf("下面是删除后的数据\n");
	SLPopFront(&s1);//头删数据
	SLPopFront(&s1);
	SLPopFront(&s1);
	SLPrint(&s1);//打印删除后的数据
	SLDestory(&s1);//销毁顺序表
}

int main()
{
	//TestSL1();
	//TestSL2();
	TestSL3();
	return 0;
}

【数据结构】顺序表的学习,数据结构的学习,数据结构,顺序表,c语言


顺序表的尾删

代码思路:我们可以通过前面的打印函数可以知道,我们是通过打印到size前面的一个下标来访问所有的元素,因此我们只需要让size往前面走一个,就可以把尾部的元素删除,可以看下图思路:
【数据结构】顺序表的学习,数据结构的学习,数据结构,顺序表,c语言

代码实现:

void SLPopBack(SL* ps1)//尾删
{
	//空
	if (ps1->size == 0)//判断删除的是否为空
	{
		return;
	}
	ps1->size--;//size--即可
}

我们依然来测试一下我们函数,看看效果是否成功实现,代码和效果图如下:

void TestSL4()
{
	SL s1;//创建动态顺序表
	SLInit(&s1);//初始化顺序表
	SLPushBack(&s1, 2);//尾增数据
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPushFront(&s1, 20);//头增的数据
	SLPushFront(&s1, 10);
	SLPushFront(&s1, 0);
	SLPushFront(&s1, 9);
	SLPrint(&s1);//打印原本的数据
	printf("上面是原本的数据\n");
	printf("--------------------------------------\n");
	printf("下面是删除后的数据\n");
	SLPopBack(&s1);//尾删数据
	SLPopBack(&s1);
	SLPrint(&s1);//打印删除后的数据
	SLDestory(&s1);//销毁顺序表
}

int main()
{
	//TestSL1();
	//TestSL2();
	//TestSL3();
	TestSL4();
	return 0;
}

【数据结构】顺序表的学习,数据结构的学习,数据结构,顺序表,c语言


顺序表的选择插入

代码思路:选择插入,即将一个值,任意插入到顺序表中的范围内,当然了口头总是不太好说清,我们对着下图来进行一一分析,我们可以记录一个end坐标记录数据的尾部,然后将值一一覆盖,pos为我们想要出入数据的位置,例如下图,当end走到pos的位置的时候,即可停止覆盖,这有点类似与我们前面的头删,将值pos之后的值全部往后挪动了一位,然后将最后重复的值被想插入的值覆盖即可。
【数据结构】顺序表的学习,数据结构的学习,数据结构,顺序表,c语言

代码实现:

void SLInsert(SL* ps1, int pos, SLDataype x)//插入数据
//pos是下标,size是数据个数,看作下标的话,他是最后一个数的下一个位置
{
	assert(ps1);//判断传来的值是否是空指针
	assert(pos >= 0 && pos <= ps1->size);//插入的值必须是再范围内(可以包括尾增)
	SLCheckCapacity(ps1);//检查空间
	// 挪动数据
	int end = ps1->size - 1;//找到尾坐标
	while (end >= pos)
	{
		ps1->a[end + 1] = ps1->a[end];//将值一一覆盖,类似于头删
		--end;
	}
	ps1->a[pos] = x;//赋值
	ps1->size++;
}

我们依然来看看函数的效果是否实现,测试代码和效果图如下:

void TestSL5()
{
	SL s1;//创建动态顺序表
	SLInit(&s1);//初始化顺序表
	SLPushBack(&s1, 2);//尾增数据
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPushFront(&s1, 20);//头增的数据
	SLPushFront(&s1, 10);
	SLPushFront(&s1, 0);
	SLPushFront(&s1, 9);
	SLPrint(&s1);//打印原本的数据
	printf("上面是原本的数据\n");
	printf("--------------------------------------\n");
	printf("下面是选择插入后的数据\n");
	SLInsert(&s1, 3, 99);
	SLInsert(&s1, 1, 2);
	SLPrint(&s1);//打印选择插入后的数据
	SLDestory(&s1);//销毁顺序表
}
int main()
{
	//TestSL1();
	//TestSL2();
	//TestSL3();
	//TestSL4();
	TestSL5();
	return 0;
}


【数据结构】顺序表的学习,数据结构的学习,数据结构,顺序表,c语言


顺序表的删除数据

代码思路:删除数据和选择插入的概念其实大差不差,首先也应当判断传过来的数是否是空指针,删除的数据在不在数据范围内,然后我们再通过图文来进行分析,如下图,先把删除的位置记录下来,当然了,和前面同理依次往前面覆盖,再打印的时候直接将size往前移一位即可把最后重复的值给去掉,达到顺序表的删除的功能。
【数据结构】顺序表的学习,数据结构的学习,数据结构,顺序表,c语言
函数代码:

void SLErase(SL* ps1, int pos)//删除数据
{
	assert(ps1);
	assert(pos >= 0 && pos < ps1->size);
	int begin = pos + 1;//记录删除数据后的位置
	while (begin < ps1->size)
	{
		ps1->a[begin - 1] = ps1->a[begin];//依次覆盖
		++begin;
	}
	ps1->size--;
}

代码实现和函数实现效果图如下:

void TestSL6()
{
	SL s1;//创建动态顺序表
	SLInit(&s1);//初始化顺序表
	SLPushBack(&s1, 2);//尾增数据
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPushFront(&s1, 20);//头增的数据
	SLPushFront(&s1, 10);
	SLPushFront(&s1, 0);
	SLPushFront(&s1, 9);
	SLPrint(&s1);//打印原本的数据
	printf("上面是原本的数据\n");
	printf("--------------------------------------\n");
	printf("下面是选择插入后的数据\n");
	SLErase(&s1, 3);//删除数据
	SLErase(&s1, 1);//删除数据
	SLPrint(&s1);//打印选择插入后的数据
	SLDestory(&s1);//销毁顺序表

}

int main()
{
	//TestSL1();
	//TestSL2();
	//TestSL3();
	//TestSL4();
	//TestSL5();
	TestSL6();
	return 0;
}

【数据结构】顺序表的学习,数据结构的学习,数据结构,顺序表,c语言


顺序表数据的查找

代码思路:顺序表数据的查找就过于简单了,我们只需要遍历数据,看看是否有对应的值,有则返回该数的下标,没有则返回**-1**。代码如下:

int SLFind(SL* ps1, SLDataype x)//顺序表数据的查找
{
	assert(ps1);//判断传来的数据是否是空指针
	for (int i = 0; i < ps1->size; i++)//遍历数组
	{
		if (ps1->a[i] == x)
			return i;//找到即返回坐标i
	}
	return -1;//没找到返回-1
}

函数测试与效果图:

void TestSL7()
{
	SL s1;//创建动态顺序表
	SLInit(&s1);//初始化顺序表
	SLPushBack(&s1, 2);//尾增数据
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPushFront(&s1, 20);//头增的数据
	SLPushFront(&s1, 10);
	SLPushFront(&s1, 0);
	SLPushFront(&s1, 9);
	SLPrint(&s1);//打印原本的数据
	printf("上面是原本的数据\n");
	printf("--------------------------------------\n");
	printf("下面是选择插入后的数据\n");
	printf("该数的下标是:%d\n",SLFind(&s1, 2));
	SLDestory(&s1);//销毁顺序表
}
int main()
{
	//TestSL1();
	//TestSL2();
	//TestSL3();
	//TestSL4();
	//TestSL5();
	//TestSL6();
	TestSL7();
	return 0;
}

【数据结构】顺序表的学习,数据结构的学习,数据结构,顺序表,c语言
讲到这里,关于顺序表的基本内容实现全部讲完了,接下来我们来看一题目练习一下把!


练习

题目链接:
【数据结构】顺序表的学习,数据结构的学习,数据结构,顺序表,c语言

思路分析:看到这个题,大家都会想到一个很通俗易懂的方法,就是开辟一个辅助数组,将所有的数放进去,然后进去排序,当然我们今天是不讲这个方法的,因为这个方法的时间复杂度过于高。我们看到这个是一个非递减顺序,可以知道最大的数都放在了后面,因此我们可以将两个数中最后的元素拿出来依次比较,然后将较大的放在nums1中的最后面,依次类推,放到最后自然而然的可以将所有数进行排序,那怎么去实现它呢?看图说话,如下图,我们记录一个坐标i1i2分别记录下两个数组中的最后一个元素,然后依次进行比较,如果i1中的数较大就放在下标j的位置,反之则把i2放进去,且如果nums1中走完了,nums2还没有,就只需要将nums2中的数据单独拿出来,放再j所在的位置即可。
【数据结构】顺序表的学习,数据结构的学习,数据结构,顺序表,c语言
代码实现如下:

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
    int i1 = m - 1;//记录第一个数组的尾坐标
    int i2 = n - 1;//第二个数组尾坐标
    int j = m + n - 1;//记录总元素的坐标
    while(i1 >= 0 &&  i2 >= 0)
    {
        if(nums1[i1] > nums2[i2])
        {
            nums1[j--] = nums1[i1--]; 
        }
        else
        {
            nums1[j--] = nums2[i2--];
        }
    }
    while(i2 >= 0)
    {
        nums1[j--] = nums2[i2--];
    }
}

运行结果:
【数据结构】顺序表的学习,数据结构的学习,数据结构,顺序表,c语言


结语:今天的内容就到这里吧,谢谢各位的观看,如果有讲的不好的地方也请各位多多指出,作者每一条评论都会读的,谢谢各位。文章来源地址https://www.toymoban.com/news/detail-743151.html


🫵🫵🫵 祝各位接下来好运连连 💞

到了这里,关于【数据结构】顺序表的学习的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [C语言][数据结构][动态内存空间的开辟]顺序表的实现!

    目录 零.必备知识 a.顺序表的底层是数组. b.数组在内存中是连续存放的. c.动态内存空间的开辟(malloc,calloc,realloc). 一.顺序表的定义与实现          1.1 顺序表的定义          1.2 顺序表的初始化          1.3 顺序表的销毁          1.4 顺序表容量的检查与调整

    2024年04月09日
    浏览(88)
  • 数据结构-顺序表的基本实现(C语言,简单易懂,含全部代码)

    今天起开始编写数据结构中的各种数据结构及算法的实现,说到顺序表,我们首先得了解下线性表。 线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串… 线性表在逻

    2023年04月08日
    浏览(42)
  • 数据结构(C语言实现)——顺序表的介绍及基本操作的实现

    今天我们来学习数据结构中的线性表,本文主要介绍一种常见的线性表——顺序表。 本文着重介绍顺序表的概念以及顺序表各种基本操作的实现过程(C语言实现),以后会更新更多的数据结构,觉得有用的朋友可以三连关注一波,一起学习。 线性表(linear list)是n个具有相

    2023年04月13日
    浏览(52)
  • 【数据结构】顺序表的实现及基本操作完整代码(C语言实现)

    顺序表:逻辑上相邻的数据元素,其物理次序也是相邻的 这里之所以要把int分别创建新名字为SqlElemType和Status,是因为实际应用时数据的类型不一定是int型,这样设置方便修改元素类型,提高代码适用性。 LocateElem的时间复杂度为O(n) InsertSq的时间复杂度为O(n) DeleteSq的时间

    2024年04月12日
    浏览(50)
  • 数据结构学习系列之顺序表的两种插入方式

    方式1: 在顺序表 末端插入 数据元素,代码如下: 示例代码: 注意事项: 1.形参传入到具有插入数据元素功能的函数后,需要做 入参合理性检查 ; 2.还需要判断此时 顺序表所存储的数据元素是否已满 ; 3.本示例代码中的 count是计数的变量 , 每次插入一个数据元素后,需

    2024年02月10日
    浏览(38)
  • 数据结构学习系列之顺序表的两种删除方式

    方式1: 在顺序表的末端删除所存储的数据元素,代码如下: 示例代码: 注意事项: 1.形参传入到具有删除数据元素功能的函数后,需要做 入参合理性检查 ; 2.还需要判断此时 顺序表所存储的数据元素是否为空 ; 3. count是计数的变量 , 每次删除一个数据元素后,需要减

    2024年02月10日
    浏览(43)
  • C语言---数据结构实验---顺序表的合并---链表的基本操作---重点解析约瑟夫问题

    实验的写法多种多样,但本文并未采用 #define 定义容量的写法,这样写已经是很老旧过时的写法。所有实验主体采用均为动态开辟,后续如果利用 C++ 来写或许会应用更多语法… 本篇展示数据结构的两个实验 其中,重点分析约瑟夫问题 实验中代码的命名风格等均与下方博客

    2024年02月16日
    浏览(70)
  • 数据结构中: 一元多项式的运算(相加,相减,相乘)------用C语言 / C++来实现。 数据结构线性表的操作和应用(顺序存储)

    线性表的操作和应用(顺序存储)。用顺序存储实现一元多项式,并进行加、减、乘运算。 (1)一元多项式结构体创建  (2)初始化 (3)一元多项式赋值             (4)打印一元多项式 (5)加法运算                        (6)减法运算 (7)乘法运算    全部代

    2024年02月01日
    浏览(64)
  • 【数据结构和算法初阶(C语言)】复杂链表(随机指针,随机链表的复制)题目详解+链表顺序表结尾

    目录  1.随机链表的复制 1.2题目描述  1.3题目分析 1.4解题: 2.顺序表和链表对比 2.1cpu高速缓存利用率 3.结语 一个长度为  n  的链表,每个节点包含一个额外增加的随机指针  random   该指针可以指向链表中的任何节点或空节点。        构造这个链表的  深拷贝 。 深拷贝

    2024年03月10日
    浏览(87)
  • 【(数据结构)- 顺序表的实现】

    先来看两张图片 数据结构是由“数据”和“结构”两词组合⽽来。 什么是数据? 常见的数值1、2、3、4…、教务系统里保存的用户信息(姓名、性别、年龄、学历等等)、网页里肉眼可以看到的信息(文字、图片、视频等等),这些都是数据 什么是结构? 当我们想要使用大

    2024年02月07日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包