数据结构之顺序表

前言

顺序表采用模块化编程思路,顺序表的实现使用3个模块,test.c—测试模块 Seqlist.c—接口函数的实现模块  seqlist.h—接口函数声明

顺序表的基本概念

顺序表是在计算机内存中通常以数组形式存储的线性表,线性表是n个具有相同特性的数据元素的有限序列线性表的顺序存储是用一组地址连续的存储单元依次存储线性表中的各个元素;采用顺序存储结构的线性表通常称为顺序表,顺序表是将表中的节点依次存放在计算机内存中一组地址连续的存储单元之中;

顺序表的结构

静态顺序表

静态顺序表:使用定长数组存储元素;

//静态顺序表
# define N 100
typedef int SeqlistDatatye;
typedef struct Seqlist
{
	SeqlistDatatye nums[N];
	int size;//记录有效数据的个数
}Seqlist;

静态顺序表的缺点:当定义容量的N太小,空间不够使用,当N过大,浪费多余的空间;

为解决这种缺点,创建了动态顺序表,可以根据需要分配空间的大小;

动态顺序表

动态顺序表:使用动态开辟的数组存储;

//动态顺序表
typedef int SLDataType;
typedef struct Seqlist
{
	SLDataType* nums;//nums指向动态开辟的数组
	int size;//记录有效数据的个数
	int capacity;//存储有效数据的容量大小,单位为每个结构体的大小
}Seqlist;

如图所示:

数据结构之顺序表_第1张图片

动态顺序表的优点:动态顺序表的容量由动态内存函数所开辟,当容量不够使用时可以增加容量capacity, 扩容方法是利用realloc()函数动态开辟一块新的空间(新空间的大小一般为原空间的两倍),若为本地扩容,直接返回原先空间的起始地址,若为异地扩容,首先将旧空间的数据拷贝到新的空间,其次释放旧的空间,最后返回新空间的起始地址

顺序表的接口实现

1.顺序表的初始化

//test.c文件

void Test()
{
	Seqlist SL;//创建顺序表
	InitSeqlist(&SL);//初始化顺序表
}
int main()
{
	Test();
	return 0;
}
//Seqlist.c文件
//初始化顺序表
void InitSeqlist(Seqlist* ps)
{
	assert(ps != NULL);
	//开辟一定容量的空间 (*ps).nums成员类型为SLDataType*,malloc返回值类型为void*,所以发生强转
	ps->nums = (SLDataType*)malloc(4 * sizeof(SLDataType*));
	//判断空间开辟是否成功
	if (ps->nums == NULL)
	{
		perror("malloc");
		exit(-1);
		//exit()函数 exit(0)表示正常退出,exit(x),x不为0表示异常退出,终止正在执行的进程;
	}
	//空间开辟成功
	ps->size = 0;
	ps->capacity = 4;//单位大小为sizeof(SLDataType*)
}

 调试窗口:

数据结构之顺序表_第2张图片

2.顺序表的销毁

//Seqlist.c文件

//顺序表的销毁
void DestroySeqlist(Seqlist* ps)
{
	assert(ps != NULL);
	free(ps->nums);
	ps->nums = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

3.顺序表显示

//Seqlist.c文件

void printSeqlist(Seqlist* ps)
{
	assert(ps != NULL);
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->nums[i]);
	}
	printf("\n");
}

4.顺序表尾插元素

//Seqlist.c文件

void Seqlistpushback(Seqlist* ps, SLDataType x)
{
	assert(ps != NULL);
	//首先应该判断顺序表是否已满,若空间已满,进行扩容;
	//当ps->size=ps->capacity说明空间已满
	if (ps->capacity == ps->size)
	{
		//用realloc()函数进行扩容,出现两种情况 1.同地扩容 2.异地扩容
		//必须新建变量接收扩容后的地址变量;
		SLDataType* tmp = (SLDataType*)realloc(ps->nums, (ps->capacity) * 2 * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc failed");
			exit(-1);
		}
		ps->capacity = (ps->capacity) * 2;
		ps->nums = tmp;
	}
	//扩容成功,尾插元素
	//总共有ps->size个有效数据,数组下标范围为0到(ps->size)-1;
	ps->nums[ps->size] = x;
	ps->size++;

}

顺序表尾插元素测试

void Test1()
{
	Seqlist SL;
	InitSeqlist(&SL);
	
	Seqlistpushback(&SL, 1);
	Seqlistpushback(&SL, 2);
	Seqlistpushback(&SL, 3);
	Seqlistpushback(&SL, 4);
	Seqlistpushback(&SL, 5);
	printSeqlist(&SL);

	DestroySeqlist(&SL);
}

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

运行结果:

5.顺序表尾删元素

void Seqlistpopback(Seqlist* ps)
{
	assert(ps != NULL);
	//首先检查顺序表中是否可以有元素删除,若不做检查,可能导致指针越界访问;

	//检查方式一
	/*if (ps->size == 0)
	{
	return;
	}*/
	//检查方式二
	assert(ps->size > 0);
	//尾删元素

	ps->size--;

}

顺序表尾删元素测试

//尾删元素测试
void Test2()
{
	Seqlist SL;
	InitSeqlist(&SL);

	Seqlistpushback(&SL, 1);
	Seqlistpushback(&SL, 2);
	Seqlistpushback(&SL, 3);
	Seqlistpushback(&SL, 4);
	Seqlistpushback(&SL, 5);
	printSeqlist(&SL);

	Seqlistpopback(&SL);
	printSeqlist(&SL);

	DestroySeqlist(&SL);
}

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

运行结果:

6.顺序表头插元素

当顺序表头插和尾插元素时,需要检查空间是否足够使用,若空间不够,需要进行扩容,为使代码不要冗余,单独封装为Checkcapacity()函数,方便使用;

扩容函数的封装

void CheckCapacity(Seqlist* ps)
{
	assert(ps != NULL);
	//首先应该判断顺序表是否已满,若空间已满,进行扩容;
	//当ps->size=ps->capacity说明空间已满
	if (ps->capacity == ps->size)
	{
		//用realloc()函数进行扩容,出现两种情况 1.本地扩容 2.异地扩容
		//必须新建变量接收扩容后的地址变量;
		SLDataType* tmp = (SLDataType*)realloc(ps->nums, (ps->capacity) * 2 * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc failed");
			exit(-1);
		}
		ps->capacity = (ps->capacity) * 2;
		ps->nums = tmp;
	}
}

顺序表头插元素的实现

void Seqlistpushfront(Seqlist* ps, SLDataType x)
{
	assert(ps != NULL);
	CheckCapacity(ps);
	//从后向前依次拷贝数据,直至首元素
	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->nums[end + 1] = ps->nums[end];
		--end;
	}
	//插入元素
	ps->nums[0] = x;
	ps->size++;
}

顺序表头插元素测试

//头插元素测试
void Test3()
{
	Seqlist SL;
	InitSeqlist(&SL);

	Seqlistpushfront(&SL, 1);
	Seqlistpushfront(&SL, 2);
	Seqlistpushfront(&SL, 3);
	Seqlistpushfront(&SL, 4);
	Seqlistpushfront(&SL, 5);
	printSeqlist(&SL);

	DestroySeqlist(&SL);

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

运行结果如下:

数据结构之顺序表_第3张图片

7.顺序表头删元素

//顺序表头删元素
void Seqlistpopfront(Seqlist* ps)
{
	assert(ps != NULL);
	assert(ps->size > 0);
	int begin = 1;
	while (begin < ps->size)
	{
		ps->nums[begin - 1] = ps->nums[begin];
		++begin;
	}
	ps->size--;

}

顺序表头删元素测试

void Test4()
{
	Seqlist SL;
	InitSeqlist(&SL);

	Seqlistpushback(&SL, 1);
	Seqlistpushback(&SL, 2);
	Seqlistpushback(&SL, 3);
	Seqlistpushback(&SL, 4);
	Seqlistpushback(&SL, 5);
	printSeqlist(&SL);

	Seqlistpopfront(&SL);
	printSeqlist(&SL);

	Seqlistpopfront(&SL);
	printSeqlist(&SL);

	DestroySeqlist(&SL);
}
int main()
{ 
    Test4();
    return 0;
}

运行结果:

数据结构之顺序表_第4张图片

8.顺序表在pos位置插入元素x

void SeqlistInsert(Seqlist* ps, int pos, SLDataType x)
{
	assert(ps != NULL);
	assert(pos >= 0 && pos <= ps->size);
	CheckCapacity(ps);
	//从顺序表最后一个元素向前拷贝,向后移动,直到pos位置为止
	int end = ps->size - 1;
	while (end >= pos)
	{
		ps->nums[end + 1] = ps->nums[end];
		end--;
	}
	ps->nums[pos] = x;
	ps->size++;
}

顺序表在pos位置插入元素x测试

void Test5()
{
	Seqlist SL;
	InitSeqlist(&SL);

	Seqlistpushback(&SL, 1);
	Seqlistpushback(&SL, 2);
	Seqlistpushback(&SL, 3);
	Seqlistpushback(&SL, 4);
	Seqlistpushback(&SL, 5);
	printSeqlist(&SL);

	SeqlistInsert(&SL, 3, 20);
	printSeqlist(&SL);

	DestroySeqlist(&SL);
}
int main()
{
    Test5();
    return 0;
}

运行结果:

数据结构之顺序表_第5张图片

9.顺序表查找某元素

//顺序表查找某个元素(查找到该元素返回下标,查找不到返回-1)
int SeqlistFind(Seqlist* ps, SLDataType x)
{
	assert(ps != NULL);
	int j = 0;
	for (j = 0; j < ps->size; j++)
	{
		if (ps->nums[j] == x)
		{
			return j;
			break;
		}
	}
	//查找不到该元素
	return -1;
}

顺序表查找某元素测试

void Test6()
{

	Seqlist SL;
	InitSeqlist(&SL);
	Seqlistpushback(&SL, 1);
	Seqlistpushback(&SL, 2);
	Seqlistpushback(&SL, 3);
	Seqlistpushback(&SL, 4);
	Seqlistpushback(&SL, 5);
	int x;
	printf("请输入要查找的元素\n");
	scanf("%d", &x);

	int pos = SeqlistFind(&SL, x);
	if (pos != -1)
	{
		SeqlistInsert(&SL, pos, x * 10);
		printSeqlist(&SL);
	}
	else
	{
		printf("查找的元素不存在\n");
	}

	DestroySeqlist(&SL);
}
int main()
{
    Test6();
    return 0;
}

运行结果:

10.顺序表删除指定位置pos处的值

void SeqlistErase(Seqlist* ps, int pos)
{
	assert(ps != NULL);
	//首先判断pos位置下标是否合法,避免数组越界访问
	assert(pos >= 0 && pos < ps->size);

	//坐标合法,从pos下一个位置从前向后拷贝
	int begin = pos + 1;
	while (beginsize)
	{
		ps->nums[begin - 1] = ps->nums[begin];
		begin++;
	}

	ps->size--;

}

顺序表删除指定位置pos处的值测试

void Test7()
{

	Seqlist SL;
	InitSeqlist(&SL);
	Seqlistpushback(&SL, 1);
	Seqlistpushback(&SL, 2);
	Seqlistpushback(&SL, 3);
	Seqlistpushback(&SL, 4);
	Seqlistpushback(&SL, 5);
	printSeqlist(&SL);
	int x;
	printf("请输入要删除的元素\n");
	scanf("%d", &x);

	int pos = SeqlistFind(&SL, x);
	if (pos != -1)
	{
		SeqlistErase(&SL, pos);
		printSeqlist(&SL);
	}
	else
	{
		printf("删除的元素不存在\n");
	}

	DestroySeqlist(&SL);
}
int main()
{
   Test7();
   return 0;
}

运行结果:

数据结构之顺序表_第6张图片

数据结构之顺序表_第7张图片

 11.头插函数改造版本SeqlistPushfront()函数

利用SeqlistInsert()函数改造头插 ,尾插函数;

//头插函数改造版
void SeqlistPushfront(Seqlist* ps, SLDataType x)
{
	SeqlistInsert(ps, 0, x);
}

SeqlistPushfront()函数测试

void Test8()
{
	Seqlist SL;
	InitSeqlist(&SL);

	SeqlistPushfront(&SL, 10);
	SeqlistPushfront(&SL, 20);
	SeqlistPushfront(&SL, 30);
	SeqlistPushfront(&SL, 40);
	SeqlistPushfront(&SL, 50);
	printSeqlist(&SL);

	DestroySeqlist(&SL);
}
int main()
{
    Test8();
    return 0;
}

运行结果:

12.尾插函数改造版本SeqlistPushback()函数

void SeqlistPushback(Seqlist* ps, SLDataType x)
{
	SeqlistInsert(ps, ps->size, x);
}

SeqlistPushback()函数测试

void Test9()
{
	Seqlist SL;
	InitSeqlist(&SL);

	SeqlistPushback(&SL, 11);
	SeqlistPushback(&SL, 12);
	SeqlistPushback(&SL, 13);
	SeqlistPushback(&SL, 14);
    SeqlistPushback(&SL, 15);
	printSeqlist(&SL);

	DestroySeqlist(&SL);
}

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

运行结果:

13.头删函数改造版本SeqlistPopfront()函数

利用SeqlistErase()函数改造头删 尾删函数;

void SeqlistPopfront(Seqlist* ps)
{
	SeqlistErase(ps, 0);
}

 SeqlistPopfront()函数测试

void Test10()
{
	Seqlist SL;
	InitSeqlist(&SL);

	Seqlistpushback(&SL, 1);
	Seqlistpushback(&SL, 2);
	Seqlistpushback(&SL, 3);
	Seqlistpushback(&SL, 4);
	Seqlistpushback(&SL, 5);
	printSeqlist(&SL);

	SeqlistPopfront(&SL);
	printSeqlist(&SL);

	DestroySeqlist(&SL);
}
int main()
{
   Test10();
   return 0;
}

运行结果:

14.尾删函数改造版本SeqlistPopback()函数

void Test11()
{
	Seqlist SL;
	InitSeqlist(&SL);

	Seqlistpushback(&SL, 1);
	Seqlistpushback(&SL, 2);
	Seqlistpushback(&SL, 3);
	Seqlistpushback(&SL, 4);
	Seqlistpushback(&SL, 5);
	printSeqlist(&SL);

	SeqlistPopback(&SL);
	printSeqlist(&SL);
	SeqlistPopback(&SL);
	printSeqlist(&SL);

	DestroySeqlist(&SL);
}
int main()
{
    Test11();
    return 0;
}

SeqlistPopback()函数测试

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

void SeqlistModify(Seqlist* ps, int pos, SLDataType x)
{
	assert(ps != NULL);
	//检查要修改某个元素的下标是否合法
	assert(pos >= 0 && pos < ps->size - 1);

	ps->nums[pos] = x;

}

顺序表修改pos位置的值测试 

void Test12()
{
	Seqlist SL;
	InitSeqlist(&SL);

	Seqlistpushback(&SL, 1);
	Seqlistpushback(&SL, 2);
	Seqlistpushback(&SL, 3);
	Seqlistpushback(&SL, 4);
	Seqlistpushback(&SL, 5);
	printSeqlist(&SL);

	SeqlistModify(&SL, 2, 100);
	printSeqlist(&SL);

	SeqlistModify(&SL, 2, 200);
	printSeqlist(&SL);

	DestroySeqlist(&SL);

}

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

运行结果:

数据结构之顺序表_第8张图片

你可能感兴趣的:(数据结构,c语言)