顺序表(详细)

目录

一.实现结构(俩种)

二.代码实现

(一).初始化

(二).扩容

(三).尾插

(四).头插

(五).尾删

(六).头删

(七).任意位置插入

(八).任意位置删除

(八)查找

(九).修改

(十).交互使用

三.完整代码


实际上就是一种从第一个位置开始向后依次连续存储数据的数组

一.实现结构(两种)

静态:

动态

二.代码实现

使用防御式编程凡涉及到指针(函数参数中有指针)的地方,全部断言,出现错误后,错误可以被快速清晰的找到.

(一).初始化

注意:

1.为什么参数传指针,形参的改变不影响实参,调试一下

void SLInit(SL* ps)//ps-p-point
{
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

(二).扩容

由于尾插,头插等函数都需要扩容,因此将扩容功能封装成函数,方便使用.

注意:

realloc有两种扩容方式

原地扩容:

异地扩容:旧空间释放,返回新空间的指针

realloc返回值void*类型

typedef int SLDataType;

SLDataType* tmp = (SLDataType*)realloc(ps->a, newCapacity*sizeof(SLDataType));

(由于reallloc返回类型是void*,但要赋值给int*,强转为int*)realloc(要扩容数组的第一个元素的指针,要扩容到多少个字节数)

void SLCheckCapacity(SL* ps)
{
	//一个数据都没存储(capacity=0),数据存满(capacity=size)这俩种情况都需要扩容
	if (ps->capacity == ps->size)//可以表示俩种情况,0==0,满==满
	{
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		//一个数据都没存,给4个字节空间
		//有数据存储,但已经存满,给俩倍空间
		SLDataType* tmp = (SLDataType*)realloc(ps->a, newCapacity*sizeof(SLDataType));
		//为啥不直接给ps->a,因为害怕realloc扩容失败,等扩容成功后,再把tmp赋值给ps->a
		if (tmp == NULL)
		{
			perror("realloc");
			exit(-1);//退出程序
		}
		ps->a = tmp;
		ps->capacity = newCapacity;
	}
}

(三).尾插

void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	ps->a[ps->size] = x;
	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++;//标号++
}

(五).尾删

注意:

1.尾删4次,size就会变成-1
数组会越界
因此每次尾删前需要判断size:size>0

2.并不是每次数组越界编译器都会检查,编译器只会抽查.(这里的数组越界会在销毁空间(free)时被编译器检查到)

void SLPopBack(SL* ps)
{
	assert(ps != NULL);
	assert(ps->size > 0);///为假,assert会报错
	ps->size--;
}

(六).头删

注意

1.和尾删一样,每次头删前也需要判断size(当前空间种数据个数)必须大于0

2.头删必须从前向后把数据向前挪动一格,不能从后向前

void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size > 0);///为假,报错
	int begin = 0;
	int end = ps->size - 1;
	while (begin < end)
	{
		ps->a[begin] = ps->a[begin + 1];
		++begin;
	}
	ps->size--;
}

(七).任意位置插入

注意

1.pos范围[0,size]   为什么可以等于size,尾插时ps->a[ps->size]这个位置也可以插入

2.插入数据都需要调用 SLCheckCapacity(ps);函数

3.pos是要插入的位置(pos指的是数组下标)

void SLInsert(SL* ps, int pos, int x)//pos是数组下标
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	SLCheckCapacity(ps);
	int begin = pos-1;
	int end = ps->size;
	while (end >= begin)
	{
		ps->a[end + 1] = ps->a[end];
		--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);//代码复用
}

(八).任意位置删除

注意:begin<size-1而不是begin<size

void SLEarse(SL* ps, int pos)
{


	assert(ps);
	assert(pos >= 0 && pos < ps->size);
    //不用检查数组a是否为空,这里顺带就检查了,pos < ps->size(ps->size为0)

	//注意控制边界,控制方式1
	//int begin = pos;
	//while (begin < ps->size - 1)//小于ps->size - 1而不是小于ps->size,防止数组越界
	//{
	//ps->a[begin] = ps->a[begin + 1];
	//++begin;
	//}
	//注意控制边界,控制方式2
	int begin = pos + 1;
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		++begin;
	}
	ps->size--;
}

代码复用

//头删
void SLPopFront(SL* ps)
{
	SLEarse(ps, 0);
}
//尾删
void SLPopBack(SL* ps)
{
	SLEarse(ps, ps->size - 1);
}

(八)查找

找到了,返回找到数的下标

找不到,返回-1

int SLSearch(SL* ps, SLDataType x)
{
	assert(ps);
	int i = 0;
	for (i = 0; i < ps->size; ++i)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
	}
	return -1;//x不在顺序表中
}

(九).修改

void Modify(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	ps->a[pos] = x;
}

(十).交互使用

SLSearch与Modify或者SLEarse可以交互使用

如果顺序表中有要找的数字,则SLSearch会返回该数字下标

而Modify或者SLEarse需要数字下标才能找到数字进行操作

void TestSeqList8()//测试查找与修改
{
	SL sl;
	SLInit(&sl);
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	SLPushBack(&sl, 5);
	PrintSeqList(&sl);


	//SLSearch可以和SLEarse交互使用
	//SLSearch如果找到要找的数会返回下标,把下标传给SLEarse这个数就会被删除
	int num = 0;
	printf("请输入你要删除的值:\n");
	scanf("%d", &num);
	int pos = SLSearch(&sl, num);//返回你要删除那个值的下标
	if (pos != -1)
	{
		SLEarse(&sl, pos);
		PrintSeqList(&sl);
	}
	else
	{
		printf("你要删除的值不在顺序表中\n");
	}


	//SLSearch可以和Modify交互使用
	//SLSearch返回下标,将下标传给Modify修改
	int y, z;
	printf("请输入你要修改的值和修改后的值:");
	scanf("%d %d", &y, &z);//输入哪个数字就会修改哪个数字
	pos = SLSearch(&sl, y);
	if (pos != -1)
	{
		Modify(&sl, pos, z);
	}
	else
	{
		printf("要修改的%d不存在", y);
	}
	PrintSeqList(&sl);
}

三.完整代码

//SeqList.h

#pragma once
#include<stdio.h>
#include<stdlib.h>//realloc,malloc
#include<assert.h>



//typedef int SLDataType;
静态存储,N太小,空间不够用,N太大,浪费空间
//#define MAX 100
//typedef struct SeqList
//{
//	SLDataType a[MAX];//开MAX个数组
//	int size;//当前数据个数
//}SL;




typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* a;//动态顺序表首元素指针
	int size;//当前存储数据个数
	int capacity;//当前存储容量
}SL;

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


void SLInit(SL* ps);//初始化
void SLCheckCapacity(SL* ps);//检查容量

void SLPushBack(SL* ps, SLDataType x);//尾插
void SLPushFront(SL* ps, SLDataType x);//头插

void SLPopBack(SL* ps);//尾删
void SLPopFront(SL* ps);//头删

void SLDestory(SL* ps);//销毁空间

void SLInsert(SL* ps, int pos, SLDataType x);//任意位置插入
void SLEarse(SL* ps, int pos);//任意位置删除

int SLSearch(SL* ps, SLDataType x);//查找,返回下标
void Modify(SL* ps, int pos, SLDataType x);//修改数组中下标为pos位置的元素,改为x


//SeqList.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"SeqList.h"

void PrintSeqList(SL* ps)
{
	int i = 0;
	for (i = 0; i < ps->size; ++i)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}

void SLInit(SL* ps)//ps-p-point
{
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}


void SLCheckCapacity(SL* ps)
{
	//一个数据都没存储(capacity=0),数据存满(capacity=size)这俩种情况都需要扩容
	if (ps->capacity == ps->size)//可以表示俩种情况,0==0,满==满
	{
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		//一个数据都没存,给4个字节空间
		//有数据存储,但已经存满,给俩倍空间
		SLDataType* tmp = (SLDataType*)realloc(ps->a, newCapacity*sizeof(SLDataType));
		//为啥不直接给ps->a,因为害怕realloc扩容失败,等扩容成功后,再把tmp赋值给ps->a
		if (tmp == NULL)
		{
			perror("realloc");
			exit(-1);//退出程序
		}
		ps->a = tmp;
		ps->capacity = newCapacity;
	}
}


void SLPushBack(SL* ps, SLDataType x)
{
	//assert(ps);
	//SLCheckCapacity(ps);
	//ps->a[ps->size] = x;
	//ps->size++;

	SLInsert(ps, ps->size, x);//代码复用
}

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++;//标号++

	SLInsert(ps, 0, x);
}



void SLPopBack(SL* ps)
{
	//assert(ps != NULL);
	//assert(ps->size > 0);///为假,报错
	//ps->size--;

	SLEarse(ps, ps->size - 1);
}



void SLPopFront(SL* ps)
{
	//assert(ps);
	//assert(ps->size > 0);///为假,报错
	//int begin = 0;
	//int end = ps->size - 1;
	//while (begin < end)
	//{
	//	ps->a[begin] = ps->a[begin + 1];
	//	++begin;
	//}
	//ps->size--;

	SLEarse(ps, 0);
}


void SLDestory(SL* ps)
{
	assert(ps);
	if (ps->a != NULL)
	{
		free(ps);
		ps->a = NULL;
		ps->capacity = ps->size = 0;
	}
}


void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	SLCheckCapacity(ps);
	int begin = pos-1;
	int end = ps->size;
	while (end >= begin)
	{
		ps->a[end + 1] = ps->a[end];
		//ps->a[end] = ps->a[end-1];
		--end;
	}
	ps->a[pos] = x;
	ps->size++;

}

void SLEarse(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	int begin = pos;
	int end = ps->size - 1;
	while (begin < end)
	{
		ps->a[begin] = ps->a[begin + 1];
		++begin;
	}
	ps->size--;

}

int SLSearch(SL* ps, SLDataType x)
{
	assert(ps);
	int i = 0;
	for (i = 0; i < ps->size; ++i)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
	}
	return -1;//x不在顺序表中
}


void Modify(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	ps->a[pos] = x;
}



//test.c  测试
#define _CRT_SECURE_NO_WARNINGS 1

#include"SeqList.h"

void TestSeqList1()
{
	SL sl;
	SLInit(&sl);
}

void TestSeqList2()//尾插
{
	SL sl;
	SLInit(&sl);
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	SLPushBack(&sl, 5);
	PrintSeqList(&sl);

}
void TestSeqList3()//头插
{
	SL sl;
	SLInit(&sl);
	SLPushFront(&sl, 1);
	SLPushFront(&sl, 2);
	SLPushFront(&sl, 3);
	SLPushFront(&sl, 4);
	SLPushFront(&sl, 5);
	SLPushFront(&sl, 6);
	PrintSeqList(&sl);
}

void TestSeqList4()//尾删
{
	SL sl;
	SLInit(&sl);
	SLPushFront(&sl, 1);
	SLPushFront(&sl, 2);
	SLPushFront(&sl, 3);
	SLPushFront(&sl, 4);
	SLPushFront(&sl, 5);
	SLPushFront(&sl, 6);
	PrintSeqList(&sl);

	SLPopBack(&sl);
	SLPopBack(&sl);
	SLPopBack(&sl);
	SLPopBack(&sl);
	SLPopBack(&sl);
	//SLPopBack(&sl);

	PrintSeqList(&sl);

}


void TestSeqList5()//尾删
{
	SL sl;
	SLInit(&sl);
	//SL* sl = NULL;
	//SLInit(&sl);

	SLPushFront(&sl, 1);
	SLPushFront(&sl, 2);
	SLPushFront(&sl, 3);
	SLPushFront(&sl, 4);
	SLPushFront(&sl, 5);
	SLPushFront(&sl, 6);
	PrintSeqList(&sl);

	SLPopFront(&sl);
	SLPopFront(&sl);
	SLPopFront(&sl);
	SLPopFront(&sl);
	SLPopFront(&sl);
	SLPopFront(&sl);
	SLPopFront(&sl);


	PrintSeqList(&sl);

}

void TestSeqList6()//任意位置插入
{
	SL sl;
	SLInit(&sl);
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	SLPushBack(&sl, 5);
	PrintSeqList(&sl);

	SLInsert(&sl, 3, 208);
	PrintSeqList(&sl);

	SLPushBack(&sl, 298);
	PrintSeqList(&sl);

	SLPushFront(&sl, 9998);
	PrintSeqList(&sl);
}


void TestSeqList7()//任意位置删除
{
	SL sl;
	SLInit(&sl);
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	SLPushBack(&sl, 5);
	PrintSeqList(&sl);


	//SLEarse(&sl, 3);

	//PrintSeqList(&sl);

	SLPopBack(&sl);
	PrintSeqList(&sl);
	SLPopFront(&sl);
	PrintSeqList(&sl);


}


void TestSeqList8()//测试查找与修改
{
	SL sl;
	SLInit(&sl);
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	SLPushBack(&sl, 5);
	PrintSeqList(&sl);


	//SLSearch可以和SLEarse交互使用
	//SLSearch如果找到要找的数会返回下标,把下标传给SLEarse这个数就会被删除
	int num = 0;
	printf("请输入你要删除的值:\n");
	scanf("%d", &num);
	int pos = SLSearch(&sl, num);//返回你要删除那个值的下标
	if (pos != -1)
	{
		SLEarse(&sl, pos);
		PrintSeqList(&sl);
	}
	else
	{
		printf("你要删除的值不在顺序表中\n");
	}


	//SLSearch可以和Modify交互使用
	//SLSearch返回下标,将下标传给Modify修改
	int y, z;
	printf("请输入你要修改的值和修改后的值:");
	scanf("%d %d", &y, &z);//输入哪个数字就会修改哪个数字
	pos = SLSearch(&sl, y);
	if (pos != -1)
	{
		Modify(&sl, pos, z);
	}
	else
	{
		printf("要修改的%d不存在", y);
	}
	PrintSeqList(&sl);
}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值