顺序表(数据结构)

数据结构-顺序表 顺序表可以分为:静态顺序表与动态顺序表此顺序表采用的是动态定义的方法,我们需要将初始化中自己创建在堆上的动态空间传给指针变量a、用a访问空间存储所需数据,而size就代表我们所存储数据的个数,capacity表示顺序表的动态空间大小;最上面的宏定义表示初始化容量设定,typedef定义的类型表示所存数据类型。 阅读详情

目录

前情提示

概念

内容

1.顺序表的定义

2.顺序表的初始化

3.顺序表的销毁

4.检查空间

5.顺序表的尾插

6.顺序表的打印

7.顺序表的尾删

8.顺序表的头插

9.顺序表的头删

10.顺序表的指定位置插入

 11.顺序表指定位置值的删除

12.顺序表的查找

13.顺序表修改pos位置的值

总代码(想直接看结果的可以看这里)

在 SeqList.h 下

在 SeqList.c 下

在 Test.c 下


前情提示

SeqList.h  用于  引用的头文件、顺序表的定义、接口的函数声明。

SeqList.c  用于  接口函数的定义。

Test.c       用于   顺序表功能的测试。


概念

线性表是最基本、最简单、也是最常用的一种数据结构。一个线性表是n个具有相同特性的数据元素的有限序列。常见的线性表:顺序表、链表、栈、队列、字符串...

线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的, 线性表在物理上存储时,通常以 数组和 链式结构的形式存储。
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
          

 顺序表分为:静态顺序表和动态顺序表

1. 静态顺序表:使用定长数组存储元素。( 空间开多了浪费,开少了不够用 )

2. 动态顺序表:使用动态开辟的数组存储。(按需申请)

静态顺序表只适用于确定知道需要存多少数据的场景。不适用于现实生活中的实际情况,所以接下来我们只讲解动态顺序表。


内容

1.顺序表的定义

在 SeqList.h 下

#pragma once//使同一个文件不会被包含(include)多次,不必担心宏名冲突。

//先将可能使用到的头文件写上
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef int SLDataType;//顺序表的类型名称,给变量定义一个易于记忆且意义明确的新名字,
//并且便于以后存储其它类型时方便改动.
//(比如我晚点想存double类型的数据,我就直接将 int 改为 double )

typedef struct SeqList
{
	SLDataType* a;//指向动态开辟的数组。
	size_t size;//有效数据个数
	size_t capacity;//空间容量
}SL;
//struct 关键字和 SeqList 一起构成了这个结构类型。
//typedef 为这个结构起了一个别名,叫 SL,即:typedef struct SeqList SL 。
//现在就可以像 int 和 double 那样直接使用 SL 定义变量。

2.顺序表的初始化

在 SeqList.h 下

#define INIT_CAPACITY 4//初始化的容量

//顺序表初始化
//我们传地址而不是传值,因为形参是实参的拷贝,形参的改变不影响实参。
void SLInit(SL* ps);

在 SeqList.c 下

#include"SeqList.h"//别忘了

void SLInit(SL* ps)
{
    assert(ps);//断言

    //用malloc申请了一块空间
	ps->a = (SLDataType*)malloc(sizeof(SLDataType)*INIT_CAPACITY);
    //表示:malloc申请开辟 sizeof(int)乘以4 即16个字节大小的空间后,强制类型转换成(int*)

    if (ps->a == NULL)//如果开辟失败
	{
		perror("malloc fail");//输出错误信息
		return;
	}
	ps->size = 0;
	ps->capacity = INIT_CAPACITY;//初始化的时候先开辟一点空间
}

提醒:

对malloc函数和sizeof操作符熟悉的可以跳过这一部分。

malloc函数内参数要求是size_t类型的,返回类型是void*。

如果分配成功则返回指向被分配内存的指针,否则返回空指针NULL。

在使用malloc开辟空间时,使用完成一定要释放空间(free),如果不释放会造内存泄漏。

malloc的头文件,在ANSI标准建议使用stdlib.h头文件,但许多C编译要求用malloc.h。

 在 Test.c 下

#include"SeqList.h"//别忘了

//用于接口函数功能的测试
void TestSeqList1()
{
	SL s;
	SLInit(&s);
}

int main()
{
	TestSeqList1();//调用测试函数
	return 0;
}

3.顺序表的销毁

在 SeqList.h 下

// 顺序表销毁
void SLDestroy(SL* ps);

在 SeqList.c 下

// 顺序表销毁
void SLDestroy(SL* ps)
{
    assert(ps);//断言,最好加上,防止有些人直接将指针初始化为 NULL,而不用SLInit()函数
	free(ps->a);//释放a
	ps->a = NULL;//归还空间
	ps->capacity = ps->size = 0;//有效数据个数和空间容量都赋值为0
    //将0赋给size,再将size赋给capacity
}

在 Test.c 下

//用于接口函数功能的测试
void TestSeqList1()
{
	SL s;
	SLInit(&s);
	SLDestroy(&s);
}

4.检查空间

在 SeqList.h 下

//检查空间,如果满了,进行增容
void SLCheckCapacity(SL* ps);

在 SeqList.c 下

扩容一般一次增容 2 倍,你也可以扩3倍、4倍。

//检查空间
void SLCheckCapacity(SL* ps)
{
	assert(ps);//断言

	//判断是否扩容,若是,则扩
	if (ps->size == ps->capacity)//若最后一个数据的下一个位置的下标等于空间容量,则需扩容
	{
	   //realloc的注意事项可看下文。
	   //很多人容易把下面这一行代码写成
       //SLDataType*tmp=(SLDataType*)realloc(ps->a,ps->capacity*2);->这只扩到8个字节
	   SLDataType*temp=(SLDataType*)realloc(ps->a,sizeof(SLDataType)*ps->capacity*2);
	   //扩的空间是原来的两倍->扩到32个字节
	   //realloc(a地址,izeof(int)*4*2)后强制类型转化,
       //从void*转化成int*类型,赋值给int*类型的temp

	   if (temp == NULL)//如果申请失败
	   {
		   perror("realloc fail");//报错
		   return;
	   }
	   ps->a = temp;//a接收realloc返回的指针,realloc不一定原地扩容,可能原地、异地
	   //如果美甲上面那行代码程序没有报错,只是巧合,刚好原地扩容了。
	   ps->capacity *= 2;//如果扩容成功,size不变,capacity是原来2倍
	}
}

提醒:

对realloc函数熟悉的可以跳过这一部分。

realloc函数返回的是void*类型的指针,指向在堆区重新开辟的内存块的起始地址,ptr是先前开辟的内存块的指针,size_t size指的是New size in bytes,新的字节数,注意不是增加的字节数,而是新开辟的那块内存空间的字节数。如果申请失败,将返回NULL,此时,原来的指针仍然有效。如果调用成功,不管当前内存段后面的空闲空间是否满足要求,都会释放掉原来的指针,重新返回一个指针。

5.顺序表的尾插

在 SeqList.h 下

// 顺序表尾插——在顺序表的最后插入一个数据
void SLPushBack(SL* ps, SLDataType x);//x为插入的数据

在 SeqList.c 下

有图可知:sz是数据个数,同时也是最后一个数据的下一个位置的下标。

//顺序表的尾插
void SLPushBack(SL* ps, SLDataType x)
{
    assert(ps);//断言
    SLCheckCapacity(ps);//扩容

    if (temp == NULL)//如果申请失败
	{
	    perror("realloc fail");//报错
		return;
	}

	//sz是数据个数,同时也是最后一个数据的下一个位置的下标
	ps->a[ps->size++] = x;
	//意思是:ps->a[ps->size] = x;
	//		 ps->size++;
}

在 Test.c 下

//用于接口函数功能的测试
void TestSeqList1()
{
	SL s;
	SLInit(&s);
	SLPushBack(&s, 1);
	SLPushBack(&s, 2);
	SLPushBack(&s, 3);
	SLPushBack(&s, 4);
	SLPushBack(&s, 5);
	SLPushBack(&s, 6);
	SLDestroy(&s);
}

6.顺序表的打印

在 SeqList.h 下

//顺序表打印
void SLPrint(SL* ps);

在 SeqList.c 下

// 顺序表打印
void SLPrint(SL* ps)
{
    assert(ps);//断言
	for (size_t i = 0; i < ps->size; ++i)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}

在 Test.c 下

//用于接口函数功能的测试
void TestSeqList1()
{
	SL s;
	SLInit(&s);
	SLPushBack(&s, 1);
	SLPushBack(&s, 2);
	SLPushBack(&s, 3);
	SLPushBack(&s, 4);
	SLPushBack(&s, 5);
	SLPushBack(&s, 6);
	SLPrint(&s);
	SLDestroy(&s);
}

7.顺序表的尾删

在 SeqList.h 下

// 顺序表尾删——在顺序表的最后删除一个数据
void SLPopBack(SL* ps);

在 SeqList.c 下

// 顺序表尾删
void SLPopBack(SL* ps)
{
    assert(ps);//断言
	//size为 0之后就不能再删除了!
	if (ps->size == 0)
	{
		return;
	}
	//或者
	//assert(ps->size>0);

	//加不加 ps->a[ps->size - 1] = 0;都无所谓
	ps->size--;
}

在 Test.c 下

//用于接口函数功能的测试
void TestSeqList1()
{
	SL s;
	SLInit(&s);
	SLPushBack(&s, 1);
	SLPushBack(&s, 2);
	SLPushBack(&s, 3);
	SLPushBack(&s, 4);
	SLPushBack(&s, 5);
	SLPushBack(&s, 6);
	SLPrint(&s);

	SLPopBack(&s);
	SLPopBack(&s);
	SLPrint(&s);

	SLDestroy(&s);
}

提醒:

若size为0之后还继续减,则size会取max(int)值。

 →

注意:

很多人到这里有一个疑问,就是顺序表可以扩容,那我尾删后可以缩容(释放部分)吗?

不能,因为操作系统的内存管理不支持,操作系统支持内存整块的申请,整块的释放。

8.顺序表的头插

思路:挪动数据(在SeqList.c中体现)

............ 

 

在 SeqList.h 下

// 顺序表头插——在顺序表的开头插入一个数据
void SLPushFront(SL* ps, SLDataType x);//x为插入的数据

在 SeqList.c 下

// 顺序表头插
void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);//断言
	SLCheckCapacity(ps);//扩容

	int end = (int)ps->size - 1;//思路理解看上图
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		--end;
	}
	ps->a[0] = x;
	ps->size++;
}

在 Test.c 下

//用于接口函数功能的测试
void TestSeqList2()
{
	SL s;
	SLInit(&s);

	SLPushFront(&s, 1);
	SLPushFront(&s, 2);
	SLPushFront(&s, 3);
	SLPushFront(&s, 4);
	SLPushFront(&s, 5);
	SLPrint(&s);
}


int main()
{
	//TestSeqList1();
	TestSeqList2();
	return 0;
}

9.顺序表的头删

思路:挪动数据(在SeqList.c中体现)

 

 .........

在 SeqList.h 下

// 顺序表头删——在顺序表的开头删除一个数据
void SLPopFront(SL* ps);

在 SeqList.c 下

// 顺序表头删
void SLPopFront(SL* ps)
{
	assert(ps);//断言
	assert(ps->size > 0);//防止size为 0的时候,跳过循环,继续减减。
	int begin = 1;//思路理解看上图
	while (begin < (int)ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		++begin;
	}
	ps->size--;
}

在 Test.c 下

void TestSeqList2()
{
	SL s;
	SLInit(&s);

	SLPushFront(&s, 1);
	SLPushFront(&s, 2);
	SLPushFront(&s, 3);
	SLPushFront(&s, 4);
	SLPushFront(&s, 5);
	SLPrint(&s);

	SLPopFront(&s);
	SLPrint(&s);
	SLPopFront(&s);
	SLPrint(&s);
	SLPopFront(&s);
	SLPrint(&s);
}

注意:头插/头删N个数据时间复杂度为0(N^2)

           尾插/尾删N个数据时间复杂度为0(N)

10.顺序表的指定位置插入

思路:挪动数据(在SeqList.c中体现)

 

 

 

 

在 SeqList.h 下

// 顺序表在pos位置插入x
void SLInsert(SL* ps, size_t pos, SLDataType x);

 在 SeqList.c 下

// 顺序表在pos位置插入x
void SLInsert(SL* ps, size_t pos, SLDataType x)
{
	assert(ps);//断言
	assert(pos >= 0 && pos <= ps->size);//保证pos在0与size之间
	//取等时相当于头插/尾插
	SLCheckCapacity(ps);//扩容

	int end = ps->size - 1;
	while (end >= (int)pos)//这里特别注意强制类型转换
    //不改动其它,只将int end改成 size_t end会走死循环
	{
		ps->a[end + 1] = ps->a[end];
		--end;
	}
	
	//或者下面这种写法
	//size_t end = ps->size;
	//while (end >pos)
	//{
	//	ps->a[end] = ps->a[end-1];
	//	--end;
	//}

	ps->a[pos] = x;
	ps->size++;
}

学会在指定位置插入值的函数后,发现头插和尾插也能用这个函数。即:

void SLPushFront(SL* ps, SLDataType x)
{
    SLInsert(ps,0,x);
}
void SLPushBack(SL* ps, SLDataType x)
{
    SLInsert(ps,ps->size,x);
}

在 Test.c 下

//用于接口函数功能的测试
void TestSeqList3()
{
	SL s;
	SLInit(&s);

	SLPushFront(&s, 0);
	SLPushFront(&s, 2);

	SLInsert(&s,0,5);
	SLPrint(&s);
}

int main()
{
	//TestSeqList1();
	//TestSeqList2();
	TestSeqList3();
	return 0;
}

 11.顺序表指定位置值的删除

思路:挪动数据(在SeqList.c中体现)

 

 

在 SeqList.h 下

// 顺序表删除pos位置的值
void SLErase(SL* ps, size_t pos);

 在 SeqList.c 下

// 顺序表删除pos位置的值
void SLErase(SL* ps, size_t pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	//注意:pos不能等于size,这里和指定位置插入不一样,
    //并且间接防止了size为0的时候,跳过循环,继续减减。
	int begin = pos + 1;
	while (begin <(int)ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		++begin;
	}
	ps->size--;
}

在 Test.c 下

void TestSeqList4()
{
	SL s;
	SLInit(&s);

	SLPushFront(&s, 1);
	SLPushFront(&s, 2);
	SLPushFront(&s, 3);
	SLPushFront(&s, 4);
	SLPushFront(&s, 5);
	SLPushFront(&s, 6);
	SLPushFront(&s, 7);
	SLPushFront(&s, 8);
	SLPushFront(&s, 9);
	SLPrint(&s);

	SLInsert(&s, 4, 666);
	SLPrint(&s);

	SLInsert(&s, 0, 666);
	SLPrint(&s);

	SLErase(&s, 4);
	SLPrint(&s);

	SLErase(&s, 4);
	SLPrint(&s);
}

int main()
{
	//TestSeqList1();
	//TestSeqList2();
	//TestSeqList3();
	TestSeqList4();
	return 0;
}

 学会删除指定位置的值的函数后,发现头删和尾删也能用这个函数。即:

void SLPopFront(SL* ps)
{
    SLErase(ps,0);
}
void SLPopBack(SL* ps)
{
    SLErase(ps,ps->size-1);
}

12.顺序表的查找

在 SeqList.h 下

// 顺序表查找
int SLFind(SL* ps, SLDataType x);//x为查找的数据

 在 SeqList.c 下

// 顺序表查找
int SLFind(SL* ps, SLDataType x)
{
	assert(ps);
	for (int i = 0; i < (int)ps->size; ++i)
	{
		if (ps->a[i] == x)//如果找到了
		{
			return i;//则返回要找的值的下标
		}
	}
	return -1;//否则返回-1
}

在 Test.c 下

void TestSeqList5()
{
	SL s;
	SLInit(&s);
	int result = 0;

	SLPushFront(&s, 1);
	SLPushFront(&s, 2);
	SLPushFront(&s, 3);
	SLPushFront(&s, 4);
	SLPushFront(&s, 5);
	SLPrint(&s);

	result=SLFind(&s, 3);
	printf("%d\n", result);

}


int main()
{
	//TestSeqList1();
	//TestSeqList2();
	//TestSeqList3();
	//TestSeqList4();
	TestSeqList5();
	return 0;
}

13.顺序表修改pos位置的值

在 SeqList.h 下

//顺序表修改pos位置的值
void SLModify(SL* ps, size_t pos, SLDataType x);//x为修改后的值

 在 SeqList.c 下

//顺序表修改pos位置的值
void SLModify(SL* ps, size_t pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);//既防止了size等于0,又规范了pos的位置
	ps->a[pos] = x;
}

在 Test.c 下

void TestSeqList6()
{
	SL s;
	SLInit(&s);

	SLPushFront(&s, 1);
	SLPushFront(&s, 2);
	SLPushFront(&s, 3);
	SLPushFront(&s, 4);
	SLPushFront(&s, 5);
	SLPrint(&s);

	SLModify(&s, 2, 1);
	SLPrint(&s);
}


int main()
{
	//TestSeqList1();
	//TestSeqList2();
	//TestSeqList3();
	//TestSeqList4();
	//TestSeqList5();
	TestSeqList6();
	return 0;
}

总代码(想直接看结果的可以看这里)

在 SeqList.h 下

#pragma once//使同一个文件不会被包含(include)多次,不必担心宏名冲突。

//使用到的头文件
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef int SLDataType;//顺序表的类型名称,给变量定义一个易于记忆且意义明确的新名字,
//并且便于以后存储其它类型时方便改动。
//(比如我晚点想存double类型的数据,我就直接将int改为double)

#define INIT_CAPACITY 4//初始化的容量

typedef struct SeqList
{
	SLDataType* a;//指向动态开辟的数组
	size_t size;//有效数据个数
	size_t capacity;//空间容量
}SL;
//struct 关键字和 SeqList 一起构成了这个结构类型。
//typedef 为这个结构起了一个别名,叫 SL,即:typedef struct SeqList SL 。
//现在就可以像 int 和 double 那样直接使用 SL 定义变量。

//基本增删查改接口

//顺序表初始化
//我们传地址而不是传值,因为形参是实参的拷贝,形参的改变不影响实参。
void SLInit(SL* ps);

// 顺序表销毁
void SLDestroy(SL* ps);

//顺序表打印
void SLPrint(SL* ps);

// 顺序表尾插——在顺序表的最后插入一个数据
void SLPushBack(SL* ps, SLDataType x);//x为插入的数据

// 顺序表尾删——在顺序表的最后删除一个数据
void SLPopBack(SL* ps);

// 顺序表头插——在顺序表的开头插入一个数据
void SLPushFront(SL* ps, SLDataType x);//x为插入的数据

// 顺序表头删——在顺序表的开头删除一个数据
void SLPopFront(SL* ps);

//检查空间,如果满了,进行增容
void SLCheckCapacity(SL* ps);

// 顺序表在pos位置插入x
void SLInsert(SL* ps, size_t pos, SLDataType x);//x为插入的数据

// 顺序表删除pos位置的值
void SLErase(SL* ps, size_t pos);

// 顺序表查找
int SLFind(SL* ps, SLDataType x);//x为查找的数据

//顺序表修改pos位置的值
void SLModify(SL* ps, size_t pos, SLDataType x);//x为修改后的值

在 SeqList.c 下

#include"SeqList.h"//别忘了

//顺序表初始化
void SLInit(SL* ps)
{
	assert(ps);//断言

	//用malloc申请了一块空间
	ps->a = (SLDataType*)malloc(sizeof(SLDataType)*INIT_CAPACITY);
    //表示:malloc申请开辟 sizeof(int)乘以4 
    //即16个字节大小的空间后,强制类型转换成(int*)

	if (ps->a == NULL)//如果开辟失败
	{
		perror("malloc fail");//输出错误信息
		return;
	}
	ps->size = 0;
	ps->capacity = INIT_CAPACITY;//初始化的时候先开辟一点空间
}

// 顺序表销毁
void SLDestroy(SL* ps)
{
	assert(ps);//断言,最好加上,防止有些人直接将指针初始化为NULL,而不用SLInit()函数
	free(ps->a);//释放a
	ps->a = NULL;//归还空间
	ps->capacity = ps->size = 0;//有效数据个数和空间容量都赋值为0
}

//检查空间
void SLCheckCapacity(SL* ps)
{
	assert(ps);
	//判断是否扩容,若是,则扩
	if (ps->size == ps->capacity)//若最后一个数据的下一个位置的下标等于空间容量,则需扩容
	{
		//realloc的注意事项可看下文。
		//很多人容易把下面这一行代码写成
        //SLDataType*tmp=(SLDataType*)realloc(ps->a,ps->capacity*2);->这只扩到8个字节
		SLDataType*temp=(SLDataType*)realloc(ps->a,sizeof(SLDataType)*ps->capacity*2);
		//扩的空间是原来的两倍->扩到32个字节
		//realloc(a地址sizeof(int)*4*2)后,
        //强制类型转化从void*转化成int*类型赋值给int*类型的temp

		if (temp == NULL)//如果申请失败
		{
			perror("realloc fail");//报错
			return;
		}
		ps->a = temp;//a接收realloc返回的指针,realloc不一定原地扩容,可能原地、异地
		////如果美甲上面那行代码程序没有报错,只是巧合,刚好原地扩容了。
		ps->capacity *= 2;//如果扩容成功,size不变,capacity是原来2倍
	}
}

//顺序表的尾插
void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);//断言
	SLCheckCapacity(ps);//扩容

	//sz是数据个数,同时也是最后一个数据的下一个位置的下标
	ps->a[ps->size++] = x;
	//意思是:ps->a[ps->size] = x;
	//		 ps->size++;
}

// 顺序表打印
void SLPrint(SL* ps)
{
	assert(ps);//断言
	for (size_t i = 0; i < ps->size; ++i)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}

// 顺序表尾删
void SLPopBack(SL* ps)
{
	assert(ps);
	//size为0之后就不能再删除了!
	if (ps->size == 0)
	{
		return;
	}
	//或者
	//assert(ps->size>0);

	//加不加ps->a[ps->size - 1] = 0;都无所谓
	ps->size--;
}

// 顺序表头插
void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);//断言
	SLCheckCapacity(ps);//扩容

	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		--end;
	}
	ps->a[0] = x;
	ps->size++;
}


// 顺序表头删
void SLPopFront(SL* ps)
{
	assert(ps);//断言
	assert(ps->size > 0);//防止size为0的时候,跳过循环,继续减减。
	int begin = 1;
	while (begin < (int)ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		++begin;
	}
	ps->size--;
}


// 顺序表在pos位置插入x
void SLInsert(SL* ps, size_t pos, SLDataType x)
{
	assert(ps);//断言
	assert(pos >= 0 && pos <= ps->size);//保证pos在0与size之间
	//取等时相当于头插/尾插
	SLCheckCapacity(ps);//扩容

	int end = ps->size - 1;
	while (end >= (int)pos)//这里特别注意强制类型转换,不然容易死循环
	{
		ps->a[end + 1] = ps->a[end];
		--end;
	}
	
	//或者下面这种写法
	//size_t end = ps->size;
	//while (end >pos)
	//{
	//	ps->a[end] = ps->a[end-1];
	//	--end;
	//}

	ps->a[pos] = x;
	ps->size++;
}


// 顺序表删除pos位置的值
void SLErase(SL* ps, size_t pos)
{
	assert(ps);//断言
	assert(pos >= 0 && pos < ps->size);
	//注意:
    //pos不能等于size,这里和指定位置插入不一样并且间接防止了size为0的时候,跳过循环,继续减减
	int begin = pos + 1;
	while (begin <(int)ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		++begin;
	}
	ps->size--;
}

// 顺序表查找
int SLFind(SL* ps, SLDataType x)
{
	assert(ps);
	for (int i = 0; i < (int)ps->size; ++i)
	{
		if (ps->a[i] == x)//如果找到了
		{
			return i;//则返回要找的值的下标
		}
	}
	return -1;//否则返回-1
}

//顺序表修改pos位置的值
void SLModify(SL* ps, size_t pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);//既防止了size等于0,又规范了pos的位置
	ps->a[pos] = x;
}

在 Test.c 下

#include"SeqList.h"//别忘了

//用于接口函数功能的测试
void TestSeqList1()
{
	SL s;
	SLInit(&s);
	SLPushBack(&s, 1);
	SLPushBack(&s, 2);
	SLPushBack(&s, 3);
	SLPushBack(&s, 4);
	SLPushBack(&s, 5);
	SLPushBack(&s, 6);
	SLPrint(&s);

	SLPopBack(&s);
	SLPopBack(&s);
	SLPrint(&s);


	SLDestroy(&s);
}

void TestSeqList2()
{
	SL s;
	SLInit(&s);

	SLPushFront(&s, 1);
	SLPushFront(&s, 2);
	SLPushFront(&s, 3);
	SLPushFront(&s, 4);
	SLPushFront(&s, 5);
	SLPrint(&s);

	SLPopFront(&s);
	SLPrint(&s);
	SLPopFront(&s);
	SLPrint(&s);
	SLPopFront(&s);

	SLPrint(&s);
}

void TestSeqList3()
{
	SL s;
	SLInit(&s);

	SLPushFront(&s, 0);
	SLPushFront(&s, 2);

	SLInsert(&s,0,5);
	SLPrint(&s);
}

void TestSeqList4()
{
	SL s;
	SLInit(&s);

	SLPushFront(&s, 1);
	SLPushFront(&s, 2);
	SLPushFront(&s, 3);
	SLPushFront(&s, 4);
	SLPushFront(&s, 5);
	SLPushFront(&s, 6);
	SLPushFront(&s, 7);
	SLPushFront(&s, 8);
	SLPushFront(&s, 9);
	SLPrint(&s);

	SLInsert(&s, 4, 666);
	SLPrint(&s);

	SLInsert(&s, 0, 666);
	SLPrint(&s);

	SLErase(&s, 4);
	SLPrint(&s);

	SLErase(&s, 4);
	SLPrint(&s);
}

void TestSeqList5()
{
	SL s;
	SLInit(&s);
	int result = 0;

	SLPushFront(&s, 1);
	SLPushFront(&s, 2);
	SLPushFront(&s, 3);
	SLPushFront(&s, 4);
	SLPushFront(&s, 5);
	SLPrint(&s);

	result=SLFind(&s, 3);
	printf("%d\n", result);

}

void TestSeqList6()
{
	SL s;
	SLInit(&s);

	SLPushFront(&s, 1);
	SLPushFront(&s, 2);
	SLPushFront(&s, 3);
	SLPushFront(&s, 4);
	SLPushFront(&s, 5);
	SLPrint(&s);

	SLModify(&s, 2, 1);
	SLPrint(&s);
}


int main()
{
	//TestSeqList1();
	//TestSeqList2();
	//TestSeqList3();
	//TestSeqList4();
	//TestSeqList5();
	TestSeqList6();
	return 0;
}

欢迎指正❀

【数据结构】顺序表 顺序表的实现 阅读详情

相关推荐

【数据结构入门】顺序表(SeqList)详解(初始化、增、删、查、改)

文章目录(1)线性表(2)顺序表1)什么是顺序表2)顺序表的定义2)顺序表的接口实现1、初始化顺序表2、销毁(释放)顺序表3、检查顺序表容量是否满了,好进行增容3、顺序表尾插4、顺序表尾删5、顺序表头插6、顺序表头删7、打印顺序表8、在顺序表中查找指定值9、在顺序表指定下标位置插入数据10、在顺序表中删除指定下标位置的数据11、查看顺序表中有效数据个数12、修改指定下标位置的数据 (1)线性表 线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结

codewinter的博客 8万+

顺序表详解

检查完后就可以开始移动了,和头插差不多,我们创建一个变量 end 记录最后一个的下标(psl->size-1),并通过它来指向要移动的数据。移动完后,x 的位置就腾出来了,再把 x 插入进去,最后再 size++,就完成了。思路:首先创建一个 end 变量用来指向要移动的数据,因为指向的是数据的下标,所以是 size 要减 1。这里有可能会出现如果内存中一个元素都没有了,size有可能减到-1的位置上,这便是越界了,但size是我们用来统计元素数量的,不可能小于0的,所以这里我们需要断言一下。

Yzl17841857589的博客 1048

数据结构之顺序表:顺序表的结构及基本操作

目录一、数据结构1.1 算法与数据结构的区别二、顺序表2.1 顺序表的基本形式【重点】2.2 顺序表的两种基本实现方式【重点】1、一体式结构:2、分离式结构:2.3 元素存储区替换与扩充1. 元素存储区的替换2. 元素存储区的扩充2.4 顺序表的操作1. 增加元素2. 删除元素2.5 Python中的顺序表 一、数据结构 数据结构指数据对象中数据元素之间的关系。 计算机只有三种数据类型:int、float、char。存储在内存中,1个int占4个字节。 1.1 算法与数据结构的区别 程序 = 数据结构

weixin_44180787的博客 5761

数据结构——顺序表详解

定义顺序表是一种线性表的存储结构,它用一组地址连续的存储单位依次存储线性表中的数据元素。从而使得逻辑上相邻的两个元素在物理位置上也相邻。顺序表具有动态分配空间、支持随机访问和顺序访问,逻辑顺序与物理顺序一致。每个元素可以都有唯一的位置,可以通过索引直接访问元素。元素可以是任意类型,包括基本数据类型、结构体等。

weixin_51785373的博客 8840

[小梅哥FPGA] 如何通过动态重配置实现FPGA时钟的实时频率/相位/占空比调整?

PLL和MMCM是实际存在的硬件电路,用以对输入时钟的负面变化,如抖动、频率变化、相位偏移、占空比失真等进行处理。基于该表,用户在初始化Clk_Wiz后,只需要计算好所需的频率、相位、占空比对应的设置值,使用Xil_Out32函数配置对应寄存器即可。通过上述步骤,在平时的开发调试过程中,亦或是一些对于时钟可能有着实时性要求的设计(如数据采集、图像处理)里,我们便可以在无需重新修改设计的前提下,通过AXI4总线来完成对时钟频率、相位的调控,从而达到缩短设计周期以及让设计适应更多场景的目的。

zgmxs的专栏 2493

Sigmastar平台WDR调试实战:从参数解析到鬼影消除的完整指南

本文提供了Sigmastar平台宽动态(WDR)技术的实战调试指南。针对逆光、运动场景下的核心痛点,系统性地解析了从多曝光采集、HDR融合到色调映射的完整管线,并重点阐述了如何通过调整曝光比、运动阈值与调整曲线等关键参数,有效消除运动鬼影、平衡暗部噪声与细节,最终实现清晰稳定的图像效果。

Jerry的专栏 926

数据结构之顺序表

前面我们已经说过了这个顺序表,是一个结构体,这个结构体包含了动态开辟的数组,有效数据的个数,已经总空间的大小,而动态开辟的数组只需要我们用指针来存储即可。int* arr;//底层是动态数组,用指针变量记录地址int size;//记录数组有效数据的个数//记录数组空间的格子数我们一般都会重定义一下,将struct seqlist 给缩短成SL,方便后续使用。因为顺序表操作的不只是整形数组,还有可能操作字符数组或者其他类型的数组,所以我们一般都会把数组的类型重定义,

2301_79973359的博客 1157

Shell编程规范及变量

文章目录一.Shell脚本1.1Shell概述1.2Shell脚本 一.Shell脚本 1.1Shell概述 Shell是Linux系统中开机自动加载的一个特殊程序,它将用户输入的指令,转换成Linux内核可以识别的语言,从而让内核执行调用硬件。 Bash是Linux系统中默认使用shell的程序,它位于/bin/bash。 1.2Shell脚本 将需要执行的命令保存到一个文件中,按照顺序执行,它不需要编译,它是解释型的 ...

夏颜的博客 3675

数据结构——顺序表

本篇为数据结构系列的第一篇文章,数据结构是一种有效地存储和管理数据的方法,在应对实际问题时的重要性不亚于算法。本系列为我在学习数据结构后对于数据结构的理解,使用的语言为C。这里提几点建议,数据结构最重要的是思想,先有思路再进行代码还原能提高学习效率,在学习时,建议多画图辅助理解,图形能更直观地表达出数据结构。

m0_74310998的博客 2398

DW1000开发笔记(一)DW1000芯片概览

一、DW1000介绍 DW1000(官方网站)是一个完全集成的低功耗射频收发器,遵循IEEE 802.15.4-2011 超宽带标准。它可以被用于双向测距或者TDOA定位系统中,精度为10cm。它使用了从3.5Ghz-6.5Ghz的6个射频频段,支持100kbps、850kbps、6.8Mbps的数据速率,并且可以在多径环境下进行处理,所以可在高反射的环境下应用。 DW1000内部最高层次的概览图如下: 二、DW1000的引脚和接口 DW1000芯片使用QFN-48封装,引脚图如下: DW1000内部

Mculover666的博客(嵌入式) 1万+

【用unity实现100个游戏之2】复刻实现经典2d平台跳跃游戏《蔚蓝 Celeste》(附工程源码)

蔚蓝》是一款备受好评的独立游戏,由游戏开发工作室开发并由发行。这款游戏于2016年首次发布,并在玩家和评论界收获了广泛赞誉。蔚蓝以其独特的艺术风格和引人入胜的故事而著称。游戏以深海为背景,玩家将扮演一个能够探索水下世界的神秘生物。游戏通过惊人的视觉表现和动态的海洋生态系统为玩家带来了令人难忘的游戏体验。无论是广阔的水下景观还是充满生机的海洋生物,蔚蓝都让玩家感受到深海的神秘和美丽。蔚蓝在玩法上注重探索和解谜。玩家可以在海底环境中自由游动,发现隐藏的地点和秘密,与各种生物互动,并解决环境谜题以继续前进。

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 4167

【数据结构初阶】顺序表专题

动态顺序表的实现 增删查改

凤年徐的博客 2851

YOLOv8首发优化:遥感目标检测 | 专为低质量遥感图像设计的边缘 - 高斯聚合(EGA)模块,解决低空间分辨率、传感器噪声、目标模糊、低光照退化和部分遮挡等限制

一种轻量级网络,其创新性地整合了专为低质量遥感图像设计的边缘 - 高斯聚合(EGA)模块。

①答疑群聊服务;②YOLO大模型知识问答系统;③计算机视觉论文生成智能体; 491

数据结构顺序表

/类型重命名,为了方便后续替换类型//定长数组int size;//顺序表当前有效的数据个数}sl;这里,我们使用了定长数组,那么它就存在一个缺陷,就是这个数组给大了,浪费空间,给小了,空间不够。//类型重命名,为了方便后续替换类型//指向动态开辟的数组int size;//顺序表当前有效的数据个数//顺序表空间可存储数据个数}sl;这里,我们使用指针类型,方便我们后续使用动态内存开辟函数来调整空间的大小。size:表示了顺序表里面存储了多少个有效数据。

2301_81291674的博客 1166

《Python等级认证CCF-GESP真题解析》专栏总目录

❤️ 专栏名称:《🌸 专栏介绍:中国计算机学会GESP《CCF编程能力等级谁》Python编程(1~8级)历届真题解析。🚀 订阅专栏:订阅后可阅读专栏内所有真题解析,真题持续更新中,限时9.9元,欢迎订阅!

人生就是一个不断学习的过程 1878

LeRobot 入门教程(四)SO-101机械臂组装教程

《SO-101机器人组装与配置指南》详细介绍了旗舰机器人SO-101的完整搭建流程。从获取3D打印零件、安装LeRobot软件和FeetechSDK,到分步组装6个关节的机械臂结构(含夹爪/手柄选项),指南提供了清晰的螺丝规格和安装位置说明。重点包括:电机ID/波特率设置方法、USB端口识别技巧、领导者/跟随者臂的校准流程,以及故障排查建议。完成组装后,用户可通过配套Python脚本校准机器人,为后续的自主学习任务做好准备。文档附有视频演示和技术支持通道,确保用户顺利完成机器人部署。

2506_90492529的博客 2582

数据结构——顺序表专题

什么是数据结构呢?· 数据结构是由“数据”和“结构”两词组合⽽来。· 概念:数据结构是计算机存储、组织数据的⽅式。· 数据结构是指相互之间存在⼀种或多种特定关系的数据元素的集合。数据结构反映数据的内部构成,即数据由那部分构成,以什么⽅式构成,以及数据元素之间呈现的结构。总结:1)能够存储数据(如顺序表、链表等结构)2)存储的数据能够⽅便查找。

optimistic_chen的博客 1543

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

【数据结构】—— 顺序表

顺序表(Sequential List)是一种基本的数据结构,它通过一组连续的存储单元来存储具有相同类型的数据元素。

ElvInR的博客 1765

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

数据结构初阶之顺序表

数据结构初阶之顺序表,很简单明了的解释和实现,相信大家看完之后一定会有所收获,刚入门的小伙伴们可不要错过哦!

2302_80214413的博客 1825

数据结构--顺序表

顺序表是数据结构中线性表的一种存储结构。它按逻辑顺序依次存储数据元素,在内存中占据连续空间。从概念分类上,可分为静态顺序表和动态顺序表。前者大小固定,后者能按需调整容量,它们都具有随机访问特性,利于高效查找元素。

2402_88461821的博客 1614
上一篇: C语言——断言assert
下一篇: 单链表(数据结构)(C语言)
outdated_socks
博客等级 码龄4年 185粉丝 17原创
评论 84
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值