C语言-数据结构-顺序表

🌈个人主页: 会编辑的果子君

💫个人格言:"成为自己未来的主人~"

目录

数据结构相关概念

顺序表

顺序表的概念和结构

线性表

顺序表分类

顺序表和数组的区别

顺序表分类

静态顺序表

动态顺序表

头插和尾插

尾插


数据结构相关概念

数据结构是由"数据"和"结构"两词组合而来。

什么是数据?常见的数值1,2,3,4.....,教务系统里保存的用户信息,(姓名,性别,年龄,学历等),网页里肉眼可以看到的信息(文字,图片,视频等等),这些都是数据。

什么是结构?

当我们想要使用大量使用同一类型的数据时,通过手动定义大量的独立的变量对于程序来说,可读性非常差,我们可以借助数组这样的数据结构将大量的数据组织在一起,结构也可以理解为组织数据方式。

概念:数据结构是计算机存储,组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的元素的集合,数据结构反映数据的内部构成,即数据由哪部分构成,以什么方式构成,以及数据元素之间呈现的结构。

总结:

1)能够存储数据结构(如顺序表,链表等结构)

2)存储的数据能够方便查找

数据结构需要用到结构体,指针(一级指针,二级指针,指针传参),结构体指针,动态内存管理

顺序表

顺序表的概念和结构

线性表

线性表是N个具有相同特性的数据元素的有限序列,线性表是一种是实际中极其有用的数据结构,常用的线性表:顺序表,链表,栈,队列,字符串.....

线性表在逻辑上是线性结构,也就是说是连续的一条直线,但是在物理结构上并不一定是连续的

线性表在物理上存储时,通常是以数组和链式结构的形式存储。

顺序表:逻辑结构是线性的,物理结构是连续的

顺序表分类

顺序表和数组的区别

顺序表的底层结构是数组,对数组的封装,实现了常用的增删改查等接口

顺序表分类

静态顺序表

使用定长数组存储元素

cpp 复制代码
typedef int SLDataType;
#define N 10
struct SeqList {
	SLDataType a[N];//定长数组
	int size; //有效数组个数

}SL;

静态顺序表的缺陷:空间给少了不够用,给多了造成空间浪费

在上面的代码中,还有一个优点在于 int 可以立即替换而不影响下面的代码执行

动态顺序表

cpp 复制代码
//动态顺序表-按需申请
typedef int SLDataType;
typedef struct SeqList {
	SLDataType* arr;//存储数据的底层逻辑
	int capacity;   //记录顺序表的空间
	int size;       //记录顺序表的当前的有效存储
}SL;

动态顺序表,可增容

静态顺序表,给定的数组长度,若不够,会导致后续的数据保存失败,数据丢失是非常严重的技术事故

给多了,会导致空间的大量浪费

cpp 复制代码
//初始化和销毁
void SLInit(SL* ps) {
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

//检查
void SLChectCapacity(SL* ps) {
	if (ps->size = ps->capacity) {
		int newCapacity = ps->capacity = 0 ? 4 : 2 * ps->capacity;
		SLDataType tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		//扩容成功
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
}
cpp 复制代码
//初始化和销毁
void SLInit(SL* ps);
void SLDestroy(SL* ps);
void SLPrint(SL* ps);//保持接口一致性

头插和尾插

尾插

空间足够,直接插入

空间不够,扩容

扩容的原则:

一次扩充一个空间,插入一个元素还不会造成看空间浪费,程序执行效率低

一次扩容固定大小的空间(10,100)

小了造成频繁扩容

大了造成空间浪费

成倍数的增加(1.5倍,2倍)

数据插入的越多,扩容的大小越来越大

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include"code.2.26.h"
//初始化和销毁
void SLInit(SL* ps) {
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

//检查
void SLCheckCapacity(SL* ps) {
	if (ps->size == ps->capacity) {
		int newCapacity = ps->capacity = 0 ? 4 : 2 * ps->capacity;
		SLDataType tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		//扩容成功
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
}
//顺序表的头插/尾插
void SLPushBack(SL* ps, SLDataType x) {
	//断言,粗暴的解决办法
	//assert(ps!=NULL);
	assert(ps);
	//if判断--温柔的解决办法
	/*if (ps == NULL) {
		return;
	}*/
	//空间不够,扩容
	SLCheckCapacity(ps);
	//空间足够,直接插入
	ps->arr[ps->size++] = x;
}
void SLDestroy(SL* ps) {

}
void SLPrint(SL* ps) {
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");
}
cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include"code.2.26.h"
void slTest01() {
	SL s1;
	SLInit(&s1);
	//测试尾插
	SLPushBack(&s1, 1);
	SLPushBack(&s1, 2);
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);
	SLPrint(&s1); //1 2 3 4
}

int main() {
	slTest01();

	return 0;
}
cpp 复制代码
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

//静态顺序表

//typedef int SLDataType;
//#define N 10
//struct SeqList {
//	SLDataType a[N];//定长数组
//	int size; //有效数组个数
//
//}SL;

//动态顺序表-按需申请
typedef int SLDataType;
typedef struct SeqList {
	SLDataType* arr;//存储数据的底层逻辑
	int capacity;   //记录顺序表的空间
	int size;       //记录顺序表的当前的有效存储
}SL;

//初始化和销毁
void SLInit(SL* ps);
void SLDestroy(SL* ps);
void SLPrint(SL* ps);//保持接口一致性
//顺序表的头部/尾部插入
void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);

//打印顺序表
void SLPrint(SL* ps);
cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include"code.2.26.h"
void slTest01() {
	SL s1;
	SLInit(&s1);
	//测试尾插
	SLPushBack(&s1, 1);
	SLPushBack(&s1, 2);
	SLPushBack(&s1, 3);
	SLPushBack(&s1, 4);

	SLErase(&s1, 1);
	SLPrint(&s1); //1 2 3 4

}

int main() {
	slTest01();

	return 0;
}
cpp 复制代码
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

//静态顺序表

//typedef int SLDataType;
//#define N 10
//struct SeqList {
//	SLDataType a[N];//定长数组
//	int size; //有效数组个数
//
//}SL;

//动态顺序表-按需申请
typedef int SLDataType;
typedef struct SeqList {
	SLDataType* arr;//存储数据的底层逻辑
	int capacity;   //记录顺序表的空间
	int size;       //记录顺序表的当前的有效存储
}SL;

//初始化和销毁
void SLInit(SL* ps);
void SLDestroy(SL* ps);
void SLPrint(SL* ps);//保持接口一致性
//顺序表的头部/尾部插入
void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);
//顺序表的头部/尾部删除
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);
//指定位置之前插入数据
//删除指定位置数据
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
//打印顺序表
void SLPrint(SL* ps);
cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include"code.2.26.h"
//初始化和销毁
void SLInit(SL* ps) {
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

//检查
void SLCheckCapacity(SL* ps) {
	if (ps->size == ps->capacity) {
		int newCapacity = ps->capacity = 0 ? 4 : 2 * ps->capacity;
		SLDataType tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		//扩容成功
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
}
//顺序表的头插/尾插
void SLPushBack(SL* ps, SLDataType x) {
	//断言,粗暴的解决办法
	//assert(ps!=NULL);
	assert(ps);
	//if判断--温柔的解决办法
	/*if (ps == NULL) {
		return;
	}*/
	//空间不够,扩容
	SLCheckCapacity(ps);
	//空间足够,直接插入
	ps->arr[ps->size++] = x;
}
void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);
	//判断是否扩容
	SLCheckCapacity(ps);
	//旧数据往后挪动一位
	for (int i = ps->size; i > 0; i++)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[0] = x;
	ps->size++;
}
//顺序表的头部/尾部删除
void SLPopBack(SL* ps) {
	assert(ps);
	assert(ps->size);

	//顺序表不为空
	ps->size--;
}
void SLPopFront(SL* ps) {
	assert(ps);
	assert(ps->size);
	
	//不为空执行挪动操作
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}
//指定位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType x) {
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);

	SLCheckCapacity(ps);
	//pos及之后的数据往后挪动一位,pos空出来
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	ps->size++;
}
//删除指定位置数据
void SLErase(SL* ps, int pos) {
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	//pos以后的数据往前挪动一位
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}
void SLDestroy(SL* ps) {

}
void SLPrint(SL* ps) {
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");
}
相关推荐
胖咕噜的稞达鸭27 分钟前
二叉树搜索树插入,查找,删除,Key/Value二叉搜索树场景应用+源码实现
c语言·数据结构·c++·算法·gitee
清风wxy2 小时前
C语言基础数组作业(冒泡算法)
c语言·开发语言·数据结构·c++·windows·算法
程序员东岸2 小时前
避坑修链表:从顺序表到单链表的那点事儿(含可跑示例与小项目串联)
数据结构·笔记·学习·程序人生·链表
懒羊羊不懒@2 小时前
算法入门数学基础
c语言·数据结构·学习·算法
OKkankan3 小时前
list的使用和模拟实现
数据结构·c++·算法·list
爱吃生蚝的于勒4 小时前
【Linux】零基础学会linux环境基础开发工具使用(yum,vim,makefile,gdb)
linux·服务器·数据结构·c++·蓝桥杯·编辑器·vim
Chloeis Syntax18 小时前
栈和队列笔记2025-10-12
java·数据结构·笔记·
404未精通的狗18 小时前
(数据结构)线性表(下):链表分类及双向链表的实现
数据结构·链表
晨非辰20 小时前
【面试高频数据结构(四)】--《从单链到双链的进阶,读懂“双向奔赴”的算法之美与效率权衡》
java·数据结构·c++·人工智能·算法·机器学习·面试
im_AMBER20 小时前
数据结构 03 栈和队列
数据结构·学习·算法