数据结构——C语言实现顺序表

数据结构——顺序表

顺序表的基本结构

数据是依次存储的,具有连续性,是数据连续性不是数字大小连续性。

顺序表分为静态和动态

静态基本就是空间是固定的,需要自己修改;

动态的没有空间就自动扩容。

建立变量

typedef int SLDataType;//方便修改创建变量
typedef struct seqList
{
	SLDataType* a;
	int size;//记录存储多少个有效数据
	int capicity;//容量空间
}SL;

这整个变量也可以叫做接口,typedef就是容易修改的,设一个变量去表示所对应的类型。

初始化与释放

//初始化
//断言很重要
void SLInit(SL* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->size = 0;
	ps->capicity = 0;
}
//初始化,先判断指针传过来的数据是否为空指针,然后再对指针内容去初始化。

//释放
void SLInit(SL* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->size = 0;
	ps->capicity = 0;
}




创建动态空间

void SLCheckCapacity(SL* ps)
{
	assert(ps);
	//扩容
	if (ps->size == ps->capicity)//判断存了数据和大小是否相等,如果相等就是满了
	{
		int newcapicity = ps->size == 0 ? 4 : ps->capicity * 2;//如果=0就返回4,不等于就返回2倍
		SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapicity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);//异常结束
		}
		ps->a = tmp;//扩容后地址,可能异地扩容所以要给一个新地址
		ps->capicity = newcapicity;//扩容成功大小
	}
}

插入数据、删除数据

头部插入数据


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[ps->size] = x;
	ps->size++;

}

头部删除数据

void SLPopFront(SL* ps)
{
	assert(ps);
	int begin = 1;//从一开始是为了覆盖下标为0的数据,达到删除效果
	assert(ps->size > 0);//所存数据必须大于等于一个
	while (begin < ps->size)//size-1才是最后一个数据的下标
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;//操作完后就把空间删除
}

尾部增加数据

在这里插入图片描述

//尾部的数据直接添加就行,因为当前的ps->a[ps->size]的下标就是在size的位置,然后size++是要确保size要指向最后一个数据的下一个起始位置
void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	ps->a[ps->size] = x;
	ps->size++;
}

尾部删除数据

在这里插入图片描述

//尾部删除就直接size直接减一不打印就行,就可以达到删除效果
void SLPopBack(SL* ps)
{
	assert(ps);
	//assert(ps);
 温柔的检查
//if (ps->size == 0)
//{
//return;
//}
// 暴力的检查
	assert(ps->size > 0);//如果报错会直接输出有错误,上述温柔的检查就直接结束
	ps->size--;  
}

指定下标增加数据)

在这里插入图片描述


void SLInsert(SL* ps, size_t pos, SLDataType x)
{
	assert(ps);
	assert(ps->size >= pos);
	assert(pos >= 0);//判断下标区间
	SLCheckCapacity(ps);//挪动前判断内存是否足够
	int end = ps->size-1;//挪动数据
	while (end >= pos)//移动到下标那位就行,从后面挪
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[ps->size] = x;//挪完后,下标就在pos的位置,直接赋值
	ps->size++;
}

指定下标删除数据

在这里插入图片描述

void SLErase(SL* ps, size_t pos)
{
	assert(ps);
	assert(ps->size > pos);//尾删就是size-1的位置
	assert(pos >= 0);
	int begin = pos+1;//这里为什么是1呢?因为如果第一个(下标为0)需要删除的话就是直接可以用下标为1的去覆盖他
	while (begin < ps->size)//数据最大的下标是size-1
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;
}
//while (begin >= pos && begin < ps->size)已经定义了begin就取最大区间就行
//{
//	ps->a[begin - 1] = ps->a[begin];
//	begin++;
//}
// 一开始写的就是这么烂,虽然说效果差不多,哈哈哈。

调试

//这里举例说一下
void TestSeqList1()
{
	//要传地址才能修改
	SL s1;
	SLInit(&s1);//初始化
	SLPushBack(&s1,1);
	SLPushBack(&s1, 2);
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPrint(&s1);

	SLDestroy(&s1);//销毁
}
int main()
{
    TestSeqList1();
	return 0;
}
//调试的话就是最好是做好一个调试一个,先别写菜单,写菜单就不那么便于调试
//调试完再写菜单

查找


int SLFind(SL* ps, SLDataType x, int begin)
{
	assert(ps);
	for (int i = begin; i < ps->size; i++)
	{
		if (ps->a[i] == x)//等于那个值就有就返回下标
		{
			return i;
		}
	}

	return -1;
}

查找删除

//分两种类型
//删除一个,删除全部

int SLFind(SL* ps, SLDataType x, int begin)
{
	assert(ps);
	for (int i = begin; i < ps->size; i++)
	{
		if (ps->a[i] == x)
		{
			return i;//返回下标
		}
	}

	return -1;
}
//首先我们要接收返回值
//假设删除4,然后从下标0开始
int SLF=SLFind(&s1, 4, 0);
if(SLF!=-1)
{
     SLErase(&s1, SLF);//调用下标删除函数
}
//删除全部
int SLF=SLFind(&s1, 4, 0);
while(SLF!=-1)
{
     SLErase(&s1, SLF);//调用下标删除函数
   SLF=SLFind(&s1, 4, SLF);//这次的下标换成上一次删除下标的位置,减少重复计算
}

源码

主函数
#define _CRT_SECURE_NO_WARNINGS 1
#include"seqList.h"
int main()
{
	SL s;
	SLInit(&s);
	int option = 0;
	int val = 0;
	do
	{
		menu();
		printf("请输入你的操作:>");
		scanf("%d", &option);
		switch (option)
		{
		case 1:
			printf("请依次输入你要尾部插入的数据,以-1结束");
			scanf("%d", &val);
			while (val != -1)
			{
				SLPushBack(&s, val);
				scanf("%d", &val);
			}
			break;
		case 2:
			SLPopBack(&s);
			break;
		case 3:
			printf("请依次输入你要在头部插入的数据,以-1结束");
			scanf("%d", &val);
			while (val != -1)
			{
				SLPushFront(&s, val);
				scanf("%d", &val);
			}
			break;
		case 4:
			SLPopFront(&s);
			break;
		case 5:
			SLPrint(&s);
			break;
		default:
			break;
		}
	} while (option != -1);

	SLDestroy(&s);

	return 0;
}
声明
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
静态顺序表
//#define N    10
//typedef int SLDataType;//方便修改创建变量
//typedef struct seqList
//{
//	SLDataType a[N];
//	int size;//记录存储多少个有效数据
//}SL;
//

//动态顺序表--按需要扩容
typedef int SLDataType;//方便修改创建变量
typedef struct seqList
{
	SLDataType* a;
	int size;//记录存储多少个有效数据
	int capicity;//容量空间
}SL;
//打印
void SLPrint(SL* ps);
//初始化
void SLInit(SL* ps);
//销毁
void SLDestroy(SL* ps);
//检查空间,如果满了,进行增容  公共检查扩容
void SLCheckCapacity(SL* ps);


// 尾插尾删
void SLPushBack(SL* ps, SLDataType x);
void SLPopBack(SL* ps);


// 头插头删
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);


//pos 下标
// 顺序表在pos位置插入x
void SLInsert(SL* ps, size_t pos, SLDataType x);
// 顺序表删除pos位置的值
void SLErase(SL* ps, size_t pos);

//查找
int  SLFind(SL* ps, SLDataType x,int begin);

#####实现函数

#define _CRT_SECURE_NO_WARNINGS 1
#include"seqList.h"


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

void SLCheckCapacity(SL* ps)
{
	assert(ps);
	//扩容
	if (ps->size == ps->capicity)
	{
		int newcapicity = ps->size == 0 ? 4 : ps->capicity * 2;
		SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapicity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->a = tmp;//扩容后地址
		ps->capicity = newcapicity;//扩容成功大小
	}
}

void SLInit(SL* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->size = 0;
	ps->capicity = 0;
}

void SLDestroy(SL* ps)
{
	assert(ps);
	if (ps->a)
	{
		free(ps->a);
		ps->a = NULL;
		ps->size = 0;
		ps->capicity = 0;
	}
}



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

void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size > 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[ps->size] = x;
	ps->size++;

}

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


void SLInsert(SL* ps, size_t pos, SLDataType x)
{
	assert(ps);
	assert(ps->size >= pos);
	assert(pos >= 0);
	SLCheckCapacity(ps);
	int end = ps->size-1;
	while (end >= pos)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[ps->size] = x;
	ps->size++;
}
void SLErase(SL* ps, size_t pos)
{
	assert(ps);
	assert(ps->size >= pos);//尾删就是size-1的位置
	assert(pos >= 0);
	int begin = pos+1;
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;
}

int SLFind(SL* ps, SLDataType x, int begin)
{
	assert(ps);

	for (int i = begin; i < ps->size; ++i)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
	}

	return -1;
}
  • 16
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值