IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 【ONE·Data || 顺序表简单实现】 -> 正文阅读

[C++知识库]【ONE·Data || 顺序表简单实现】

作者:recommend-item-box type_blog clearfix

总言

??C语言简单实现顺序表的各个流程,代码解释在注释中。


??

seqlist.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>


//定义顺序表:顺序表的定义方式和通讯录类似
typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* x;//用于存储数据的数组,即顺序表
	int size;//顺序表中实际数据个数
	int capacity;//顺序表容量空间大小
}SL;



void SLInit(SL* ps);
void SLPrint(SL* ps);
void SLDestory(SL* ps);
int SLFind(SL* ps, SLDataType x);
void SLModify(SL* ps, int pos, SLDataType x);
//顺序表头插、头删:O(N)
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);
//顺序表尾插、尾删:O(1)
void SLPushBack(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
//顺序表pos位置处的插入、删除:可替代头删头插、尾删尾插
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);


??
??

text.c

#include"seqlist.h"

//写代码时的检测函数
testsl()
{
	SL s1;
	SLInit(&s1);
	//无数据时头插检查
	SLPushFront(&s1, 1);
	SLPrint(&s1);
	//有数据时头插检查
	SLPushFront(&s1, 2);
	SLPushFront(&s1, 3);
	SLPrint(&s1);

	//有数据时顺序表尾插
	SLPushBack(&s1, 5);
	SLPushBack(&s1, 6);
	SLPrint(&s1);
	//无数据时顺序表尾插
	SL s2;
	SLInit(&s2);
	SLPushBack(&s2, 6);
	SLPushBack(&s2, 5);
	SLPrint(&s2);

}
testsl1()
{
	SL s1;
	SLInit(&s1);
	SLPushFront(&s1, 1);
	SLPushFront(&s1, 2);
	SLPushFront(&s1, 3);
	SLPushFront(&s1, 4);
	SLPushFront(&s1, 5);
	SLPushFront(&s1, 6);
	SLPrint(&s1);
	//检查头删
	SLPopFront(&s1);
	SLPopFront(&s1);
	SLPrint(&s1);
	//检查尾删
	SLPopBack(&s1);
	SLPopBack(&s1);
	SLPrint(&s1);
}

testsl2()
{
	SL s1;
	SLInit(&s1);
	//测试pos插入:头插
	SLInsert(&s1, 0, 1);
	SLPrint(&s1);
	//测试pos插入
	SLInsert(&s1, 1, 2);
	SLPrint(&s1);
	SLInsert(&s1, 1, 3);
	SLPrint(&s1);
	SLInsert(&s1, 2, 4);
	SLPrint(&s1);
	SLInsert(&s1, 2, 5);
	SLPrint(&s1);
	SLInsert(&s1, 2, 7);
	SLPrint(&s1);
	//测试pos插入:尾插
	SLInsert(&s1, s1.size, 4);
	SLPrint(&s1);

	//测试pos删除:头删
	SLErase(&s1, 0);
	SLPrint(&s1);
	//测试pos删除:
	SLErase(&s1, 0);
	SLPrint(&s1);
	SLErase(&s1, 2);
	SLPrint(&s1);
	SLErase(&s1, 2);
	SLPrint(&s1);
	//测试pos删除:尾删
	SLErase(&s1, s1.size-1);
	SLPrint(&s1);
}

int main(void)
{
	//SL s1;//创建一个顺序表
	//SLInit(&s1);//初始化顺序表:函数要改变顺序表(结构体)数据,故需要址传递

	//写代码时的检测函数
	//testsl();
	//testsl1();
	//testsl2();

	//主函数中的功能可仿照通讯录来实现,比如:添加一个菜单,运用switch语句做到反复操作等,此处略
}

??
??

seqlist.c

#include"seqlist.h"




//顺序表的使用:主要功能为:顺序表初始化、头插、头删、尾插、尾删、pos位置(自由位置/中间位置)插入、删除、顺序表打印、查找修改、销毁、辅助扩容函数




//顺序表初始化
void SLInit(SL* ps)
{
	//简介:通常情况下,顺序表初始化有两种方式,其一,在初始化时就进行动态开辟,其二,若此处不进行动态开辟,则需要留意此处细节!
	//对于初始化中不进行动态开辟时,可将首次动态开辟数组和后续数组扩容放在一起实现(即辅助扩容函数),因为后续头插、尾插时,都要检查顺序表的容量空间是否充裕。
	
	//此处采用将首次动态开辟数组和后续扩容放置一起的初始化方式
	assert(ps);//对于指针,判空操作很重要!如果有成百上千行代码,一旦某行出现空指针问题,维护起来十分麻烦,严重影响项目进程。
	ps->capacity = ps->size = 0;
	ps->x = NULL;
}


//辅助扩容函数
void CheckSL(SL* ps)
{
	//简介://此处先检查容量空间,若空间不够,则需要扩容处理:
	//1、后续扩容检擦需要用到capacity(与size比较),由于初始化顺序表时未曾进行首次扩容,因此要对capacity进行判断,分为两种情况,其一为首次使用顺序表(capacity=0),其二为顺序表容量空间满时(capacity≠0)
	//2、此处直接使用了realloc函数而未用malloc函数,是根据realloc函数的特性:第一形参为空指针,等同于malloc;第二形参为0,等同于free将释放内存块。间接表明未在初始化时扩容这种写法的一个方便之处。
	assert(ps);
	if (ps->capacity == ps->size)//判断是否需要扩容
	{
		int tmpcapacity = (ps->capacity == 0 ? 4 : ps->capacity * 2);//判断需要哪种类型的扩容
		SLDataType* tmpx = (SLDataType*)realloc(ps->x, sizeof(SLDataType) * tmpcapacity);//ps->x有null的情况和非null的情况
		if (tmpx == NULL)//realloc扩容有失败可能,因此不能直接使用ps接收,需要一个临时变量并对扩容后的结果进行判断
		{
			perror("CheckSL::realloc");
			exit(-1);
		}
		//成功扩容,更新数据
		ps->x = tmpx;
		ps->capacity = tmpcapacity;

	}
}


//顺序表头插
void SLPushFront(SL* ps, SLDataType x)
{
	//简介:顺序表头插,即在顺序表头部插入一个新的数据
	//由于此处顺序表是由数组实现的,数组在内存空间中连续存储,因此要头插一个新的数据,即意味着在数组空间足够的情况下,将原先数据都往后挪动一个位置
	//需要注意的细节:
	//1、保证顺序表空间足够(数组空间),则需要在每次使用头插函数时,都进行扩容检查(辅助扩容函数的功能之一)
	//2、如何挪动数组数据?为了保证数组元素不被覆盖,在内存空间充裕的情况下,先后再前(先挪动后面的数据,再挪动前面的数据)
	//3、头插函数实际可通过pos位置插入函数实现

	assert(ps);
	//扩容检查
	CheckSL(ps);//注意传参
	//挪动数据:此处写法有多种,注意逻辑正确即可。此处头插对顺序表为空时成立。
	int end = ps->size;
	while (end)
	{
		ps->x[end] = ps->x[end - 1];
		end--;//此处end--不能直接放在while条件判断中,因为end--在条件判断完成后会自减,而循环体内又使用到了end变量,此处会出错
	}
	//在头部放入新数据
	ps->x[0] = x;
	ps->size++;


	//可用pos插入函数实现头插
	//SLInsert(ps, 0, x);

}



//顺序表尾插
void SLPushBack(SL* ps, SLDataType x)
{
	//简介:顺序表尾插,即在顺序表末尾(数组末)插入一个新的数据,相对于头插较为容易,仍旧需要关注扩容问题
	assert(ps);
	CheckSL(ps);
	ps->x[ps->size] = x;
	ps->size++;
	//此处尾插对顺序表为空时成立。

	//可用pos插入函数实现尾插
	//SLInsert(ps, ps->size, x);
}



//顺序表尾删
void SLPopBack(SL*ps)
{
	//简介:顺序表尾删,即删除顺序表最末尾的数据
	
	//注意事项:
	//1、关于是否要对被删除数据做处理?
	/*	实际上没有必要,例如,将被删除数据赋值为-1以此来表示该数据不存在,但也会有-1本身就是顺序表中一个数据的情况,即没有多余数值可提供该需求
	因此实际操作中只需要将size数据实际个数做出更改即可。以此达到访问不到顺序表最末尾数据的效果。*/

	//2、对size变量的细节处理?
	/*	size在顺序表中表示实际数据个数,通常实际使用中有范围下限(最小值),因此使用尾删操作时,不能无限删下去,这样会造成size变为负值,而以负值访问数组是一种越界情况。
	因此尾删时需要对数据个数做检查。*/

	//ps:此处关于越界不报错的原因:
	/*	大概几率下,malloct等出错,在free处才显示报错。此外,关于越界是否报错,取决于编译器,系统对越界的检查,属于设岗抽查,类似于交警拦违规驾驶。*/

	assert(ps);
	assert(ps->size > 0);//检查size下限值
	ps->size--;

	//可用pos删除函数实现尾插
}



//顺序表头删
void SLPopFront(SL* ps)
{
	//简介:顺序表头删,删除顺序表首数据。实际操作即将数组元素往前挪动覆盖即可,仍旧需要对size的下限值做判单。
	assert(ps);
	assert(ps->size > 0);
	//此处实现方法有很多,注意逻辑即可。
	//比如此处取begin=0,使用begin与begin+1,则判断循环结束的条件是begin+1<size;若取begin=1,使用begin与begin-1,则判断循环结束的条件是begin<size
	int begin = 0;
	while(begin < ps->size-1)
	{
		ps->x[begin] = ps->x[begin + 1];
		begin++;
	}
	ps->size--;

	//可用pos删除函数实现尾插

}



//在pos位置处插入数据
void SLInsert(SL* ps, int pos ,SLDataType x)
{
	//简介:在pos处插入新数据,即在数组中插入数据,所用方法和头插相似,例如,输入pos=2,则在ps->x[pos]的位置需要插入新输入的数据
	//注意事项:
	//1、仍旧需要做扩容检查,此外,还需对输入的pos位置进行检查,即pos需要在数组内部[0,size],pos=0即头插,pos=size即尾插

	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	CheckSL(ps);
	//挪动数据:此处方法有很多,注意逻辑。
	int  end = ps->size;
	while (end-1>=pos)
	{
		ps->x[end] = ps->x[end - 1];
		end--;
	}
	//插入数据:
	ps->x[pos] = x;
	ps->size++;
}



//在pos位置处删除数据
void SLErase(SL* ps, int pos)
{
	//简介:删除pos处的数据,和头删一样使用覆盖法,其余注意事项相同(size下限值,pos范围:[0,size),此时尾部size不能包含进来)。
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	int begin = pos;//此处使用的是begin与begin+1,判断循环界线即begin+1<size
	while (begin < ps->size - 1)
	{
		ps->x[begin] = ps->x[begin + 1];
		begin++;
	}
	ps->size--;
}



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


//顺序表查找
int SLFind(SL* ps, SLDataType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; ++i)
	{
		if (ps->x[i] == x)
			return i;
	}
	return -1;
}

//顺序表修改:可结合顺序表查找使用,如此就不用特意写该函数:单链表中有演示
void SLModify(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	ps->x[pos] = x;
}

//顺序表销毁
void SLDestory(SL* ps)
{
	assert(ps);
	if (ps->x)
	{
		free(ps->x);
		ps->x = NULL;
		ps->size = ps->capacity = 0;
	}
}

??
??

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-30 08:30:43  更:2022-04-30 08:32:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 22:39:32-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码