目录
【1】数据结构概述
【1.1】什么是数据结构?
【1.2】数据结构分类
【1.3】数据结构术语
【2】数据结构特点
【3】静态顺序表
【3.1】静态顺序表概念及结构
【3.2】静态顺序表定义数据结构和接口
【3.3】静态顺序表初始化
【3.4】静态顺序表头插入
【3.5】静态顺序表尾插入
【3.6】静态顺序表头删除
【3.7】静态顺序表尾删除
【3.8】静态顺序表在指定位置插入
【3.9】静态顺序表在指定位置删除
【3.10】静态顺序表打印
【3.11】静态顺序表查找返回下标
【3.12】静态顺序表修改
【3.13】静态顺序表检测空间是否满
【3.14】静态顺序表检测是否为空
【3.15】静态顺序表获取有效数据个数
【1】数据结构概述
【1.1】什么是数据结构?
官方解释:数据结构是一门研究非数值计算的程序设计问题中的操作对象,以及他们之间的关系和操作等相关问题的学科。
大白话:数据结构就是把数据元素按照一定的关系组织起来的集合,用来组织和存储数据。
【1.2】数据结构分类
逻辑结构分类:
逻辑结构是从具体问题中抽象出来的模型,是抽象意义上的结构,按照对象中数据元素之间的相互关系分类,也是我们后面课题中需要关注和讨论的问题。
- 集合结构:
结合结构中数据元素出了属于同一集合外,他们之间没有任何其他关系。
- 线性结构:
线性结构中的数据元素之间存在一对一的关系。
- 树形结构:
树形结构中的数据元素之间存在多对一的层次关系。
- 图形结构:
图形结构的数据元素是多对多的关系。
物理结构分类:
逻辑结构在计算机中真正的表示方式(又称映像)称为物理结构,也可以叫做存储结构,常见的物理结构有顺序存储结构、链式存储结构。
顺序存储结构:
逻辑结构在计算机中真正的表示方式(又称映像)称为物理结构,也可以叫做存储结构,常见的物理结构有顺序存储结构、链式存储结构。
顺序存储结构存在一定的弊端,就想生活中排队时,会有人插队也有可能有人突然离开,这时候整个结构都处于变化之中,此时就需要链式存储结构。
是把数据元素存放在任意的存储单元里面,这组存储单元可以是连续的,也可以是不连续的。此时,数据元素之间的关系,并不能反映元素间的逻辑关系,因此链式存储中引进了一个指针存放数据元素的地址,这样通过地址就可以找到相关联数据元素的位置。
【1.3】数据结构术语
抽象数据类型:(Abstract Data Type,简称ADT)是指一个数学模型以及定义在该模型上的一组操作。抽象数据类型的定义仅取决于它的一组逻辑特性,而与其在计算机内部如何表示和实现无关,即不论其内部结构如何变化,只要它的数学特性不变,都不影响其外部的使用。
抽象数据类型和数据类型实质上是一个概念。例如,各个计算机都拥有的“整数”类型是一个抽象数据类型,尽管它们在不同处理器上实现的方法可以不同,但由于其定义的数学特性相同,在用户看来都是相同的。因此,“抽象”的意义在于数据类型的数学抽象特性。
数据结构的表示(存储结构)用类型定义( typedef)描述。数据元素类型约定为Data。
【2】数据结构特点
线性结构的特点是:
在数据元素的非空有限集合中。
- 存在唯一的一个被称为"第一个"的数据元素
- 存在唯一的一个被称为“最后一个”的数据元素
- 除了第一个之外,结合中的每个数据元素均只有一个前驱
- 除了最后一个之外,集合中每个数据元素均只有一个后继
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
线性表示一个相当灵活的数据结构,它的长度可以根据需要增长或缩短,即对线性表的数据元素不仅可以进行访问,还可以进行插入和删除等。
【3】静态顺序表
【3.1】静态顺序表概念及结构
顺序表是指用一组地址连续的内存单元依次存储线性表的数据元素
通常都用数组来描述数据结构中的顺序存储结构。由于线性表的长度可变,且所需最大存储空间随问题不同而不同,则在C语言中可用动态内存分配一维数组,
如下描述:
【3.2】静态顺序表定义数据结构和接口
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
/* 静态顺序表数据结构 */
#define N 10
typedef int SQLType;
typedef struct SeqList
{
SQLType data[N]; // 数据存储区。
size_t size; // 当前数据去有效数据个数。
}SeqList;
/* 静态顺序表初始化 */
void SeqListInit(SeqList* pSQ);
/* 静态顺序表头插入 */
void SeqListPushFront(SeqList* pSQ, SQLType data);
/* 静态顺序表尾插入 */
void SeqListPushBack(SeqList* pSQ, SQLType data);
/* 静态顺序表头删除 */
void SeqListPopFront(SeqList* pSQ);
/* 静态顺序表尾删除 */
void SeqListPopBack(SeqList* pSQ);
/* 动态顺序表在指定位置插入 */
void SeqListInsert(SeqList* pSQ, size_t pos, SQLType data);
/* 动态顺序表在指定位置删除 */
void SeqListErase(SeqList* pSQ, size_t pos);
/* 静态顺序表打印 */
void SeqListPrint(SeqList* pSQ);
/* 静态顺序表查找返回下标 */
int SeqListFind(SeqList* pSQ, SQLType data);
/* 静态顺序表修改 */
void SSeqListModifi(SeqList* pSQ, size_t pos, SQLType data);
/* 静态顺序表检测满了返回false没满返回true */
bool SeqListCheck(SeqList* pSQ);
/* 静态顺序表检测是否存在数据个数有数据返回false没有数据返回true */
bool SeqListEmpty(SeqList* pSQ);
/* 静态顺序表获取有效数据个数 */
bool SeqListGetSize(SeqList* pSQ);
【3.3】静态顺序表初始化
// 静态顺序表初始化函数实现
void SeqListInit(SeqList* pSQ)
{
// 断言:保护形参指针不为NULL
assert(pSQ);
memset(pSQ->data, 0, sizeof(pSQ->data));
pSQ->size = 0;
}
【3.4】静态顺序表头插入
// 静态顺序表 - 头插入
void SeqListPushFront(SeqList* pSQ, SQLType data)
{
// 断言:保护形参指针不为NULL
assert(pSQ);
// 判断存储空间大小
if (!SeqListCheck(pSQ))
{
printf("SeqList Full!\n");
return;
}
// 移动数据
size_t end = pSQ->size;
while (end > 0)
{
pSQ->data[end] = pSQ->data[end - 1];
end--;
}
// 数据插入头部
pSQ->data[0] = data;
pSQ->size++;
}
【3.5】静态顺序表尾插入
// 静态顺序表 - 尾插入
void SeqListPushBack(SeqList* pSQ, SQLType data)
{
// 断言:保护形参指针不为NULL
assert(pSQ);
// 判断存储空间大小
if (!SeqListCheck(pSQ))
{
printf("SeqList Full!\n");
return;
}
// 程序走到这里说明数组中的数据没有满!
pSQ->data[pSQ->size++] = data;
}
【3.6】静态顺序表头删除
// 静态顺序表 - 头删除
void SeqListPopFront(SeqList* pSQ)
{
// 断言:保护形参指针不为NULL
assert(pSQ);
// 判断顺序表中是否还有有效的数据
if (!SeqListEmpty(pSQ))
{
printf("SeqList Empty!\n");
return;
}
// 移动数据
int begin = 0;
while(begin < pSSQ->size - 1)
{
pSQ->data[begin] = pSQ->data[begin + 1];
begin++;
}
pSQ->size--;
}
【3.7】静态顺序表尾删除
// 静态顺序表 - 尾删除
void SeqListPopBack(SeqList* pSQ)
{
// 断言:保护形参指针不为NULL
assert(pSQ);
// 判断顺序表中是否还有有效的数据
if (!SeqListEmpty(pSQ))
{
printf("SeqList Empty!\n");
return;
}
// 程序走到这里说明数组中还有有效数据
pSQ->size--;
}
【3.8】静态顺序表在指定位置插入
// 动态顺序表 - 在指定位置插入
void SeqListInsert(SeqList* pSQ, size_t pos, SQLType data)
{
// 断言保护形参指针变量不为NULL
assert(pSQ);
// 判断存储空间大小
if (!SeqListCheck(pSQ))
{
printf("SeqList Full!\n");
return;
}
// 移动数据
int end = SeqListGetSize(pSQ) + 1;
while (end > pos)
{
pSQ->data[end] = pSQ->data[end - 1];
end--;
}
pSQ->data[pos] = data;
pSQ->size++;
}
【3.9】静态顺序表在指定位置删除
// 动态顺序表 - 在pos位置删除
void SeqListErase(SeqList* pSQ, size_t pos)
{
// 断言保护形参指针变量不为NULL
assert(pSQ);
// 判断动态顺序表中是否还有数据
if (!SeqListEmpty(pSQ))
{
printf("SeqList Empty!");
return;
}
size_t begin = pos;
while (begin < pSSQ->size)
{
pSQ->data[begin] = pSQ->data[begin + 1];
begin++;
}
--pSQ->size;
}
【3.10】静态顺序表打印
// 静态顺序表 - 打印
void SeqListPrint(SeqList* pSQ)
{
// 断言:保护形参指针不为NULL
assert(pSQ);
for (int i = 0; i < pSQ->size; i++)
{
printf("%d\t",pSQ->data[i]);
}
printf("\n");
}
【3.11】静态顺序表查找返回下标
// 静态顺序表 - 查找 - 返回下标
int SeqListFind(SeqList* pSQ, SQLType data)
{
// 断言:保护形参指针不为NULL
assert(pSQ);
// 判断顺序表中是否还有有效的数据
if (!SeqListEmpty(pSQ))
{
printf("SeqList Empty!\n");
return -1;
}
// 程序走到这里说明数组中有元素,找到下表并且返回
for (int i = 0; i < pSQ->size; i++)
{
if (pSQ->data[i] == data)
return i;
}
return -1;
}
【3.12】静态顺序表修改
// 静态顺序表 - 修改
void SeqListModifi(SeqList* pSSQ, size_t pos, SQLType data)
{
// 断言:保护形参指针不为NULL
assert(pSQ);
pSQ->data[pos] = data;
}
【3.13】静态顺序表检测空间是否满
// 静态顺序表 - 检测 - 满了返回false - 没满返回true
bool SeqListCheck(SeqList* pSQ)
{
// 断言:保护形参指针不为NULL
assert(pSSQ);
return pSQ->size != N;
}
【3.14】静态顺序表检测是否为空
// 静态顺序表 - 检测是否存在数据个数 - 有数据返回true - 没有数据返回false。
bool SeqListEmpty(SeqList* pSSQ)
{
// 断言:保护形参指针不为NULL
assert(pSQ);
return pSQ->size != 0;
}
【3.15】静态顺序表获取有效数据个数
// 静态顺序表 - 获取有效数据个数
bool SeqListGetSize(SeqList* pSSQ)
{
// 断言:保护形参指针不为NULL
assert(pSQ);
return pSQ->size - 1;
}