目录
二、抽象数据类型(Abstract Data Type,ADT)
前言
本博客为本人在学习数据结构路途上的一些学习心得,如觉得对有你有所帮助,还希望留下一个赞。由于博主只是一名大一新生,如果博文中出现错误,欢迎指正。如果想要转载,附上链接就行。
引言
数据类型是什么?这是一个看似简单却又深奥的问题。数据类型是编程语言中用来描述数据特征和操作的一种分类方式,它决定了数据在内存中的存储形式、取值范围、运算规则等。数据类型就像是编程世界中的基本元素,没有它们,就没有程序。
数据类型有很多种,不同的编程语言可能有不同的分类方法和命名规则。但一般来说,我们可以把数据类型分为两大类:数值型和非数值型。数值型数据包括整数、浮点数、复数等,它们可以进行加减乘除等算术运算。非数值型数据包括布尔值、字符串、列表、元组、字典等,它们可以进行逻辑判断、文本处理、数据组织等操作。
你可能会问,为什么要有这么多种数据类型呢?难道不能用一个统一的格式来表示所有的数据吗?答案是不行。因为不同的数据类型有不同的特点和用途,如果我们把所有的数据都用同一种类型来表示,那么就会造成很多问题。比如,如果我们用整数来表示温度,那么我们就无法区分0℃和0.5℃;如果我们用浮点数来表示性别,那么我们就无法确定男女之间的差别;如果我们用字符串来表示日期,那么我们就无法进行日期计算;如果我们用列表来表示图形,那么我们就无法绘制出图形的形状。
所以,了解数据类型的概念和分类,是学习数据结构的第一步。只有掌握了数据类型的特点和区别,才能更有效地构建和使用数据结构来解决问题。
一、数据类型的定义和作用
定义
一组性质相同的值的集合以及定义于这个值集合上的一组操作的总称。
数据类型=值的集合+值集合上的一组操作
作用
约数变量或常量的取值范围和操作
例子:
在C语言中定义i为int类型,表示i是[min,max]范围的整数(max和min的大小由编译器决定,在vs2022中max为2^31-1,,min为-2^31),在这个整数集上可以进行+、-、*、\、%等操作。
二、抽象数据类型(Abstract Data Type,ADT)
定义
是指一个数学模型以及定义在此数学模型上的一组操作。它只描述了数据类型的特征和操作,而不涉及具体的实现细节,不需要关心数据类型是如何在内存中存储和组织的,也不需要知道对数据类型进行操作的算法是什么。只需要知道数据类型可以表示什么样的值,以及可以对数据类型进行什么样的操作。
例子
在考虑寻找从A地到B地最短路径时我们可以把所有城市和城市直间的道路抽象为图,以下是图示和具体代码。
这个图像中,我们把各地的位置和他们之间的路径抽象为如图所示的数学模型,它拥有两个数据类型,分别为顶点和边。在C++中,我们通常会使用Class类来对抽象数据类型进行封装形成具体的数据结构,在C语言中则一般使用Struct结构体进行封装。下面是C++的实现代码,看不懂也没关系,我会在以后的文章进行进行具体介绍。
//定义一个顶点类,它包含一个顶点的标识符和一个指向邻接顶点列表的指针
class Vertex
{
public:
// 顶点的标识符,可以是任意类型
int id;
// 指向邻接顶点列表的指针
std::list<Vertex*> adj;
// 构造函数,初始化顶点的标识符
Vertex(int id) {
this->id = id;
}
};
//定义一个图类,它包含一个顶点集合和一些图的操作:
class Graph
{
public:
// 顶点集合,可以是任意容器类型
std::vector<Vertex*> vertices;
// 构造函数,初始化顶点集合为空
Graph()
{
vertices.clear();
}
// 添加一个顶点到图中,返回指向该顶点的指针
Vertex* addVertex(int id)
{
// 创建一个新的顶点对象
Vertex* v = new Vertex(id);
// 将该顶点对象添加到顶点集合中
vertices.push_back(v);
// 返回该顶点对象的指针
return v;
}
// 添加一条边到图中,连接两个给定的顶点
void addEdge(Vertex* u, Vertex* v)
{
// 将v添加到u的邻接列表中
u->adj.push_back(v);
// 如果是无向图,还要将u添加到v的邻接列表中
v->adj.push_back(u);
}
// 打印图的信息,包括顶点数、边数和邻接表
void print()
{
// 获取顶点数
int n = vertices.size();
// 初始化边数为0
int m = 0;
// 遍历每个顶点
for (int i = 0; i < n; i++)
{
// 获取当前顶点的指针和标识符
Vertex* u = vertices[i];
int uid = u->id;
// 获取当前顶点的邻接列表的大小(即度数)
int d = u->adj.size();
// 累加边数(如果是无向图,要除以2)
m += d;
// 打印当前顶点的标识符和邻接列表
std::cout << "Vertex " << uid << ":";
for (auto v : u->adj) {
std::cout << " " << v->id;
}
std::cout << "\n";
}
// 如果是无向图,要除以2
m /= 2;
// 打印顶点数和边数
std::cout << "The graph has " << n << " vertices and " << m << " edges.\n";
}
};
实现
定义:
抽象数据类型的实现是指在编程语言中,用具体的数据结构和算法来表示和操作抽象数据类型。
原则:
- 封装:抽象数据类型的内部实现细节应该对外部用户隐藏,只提供一个公共的接口(访问),让用户通过接口来使用抽象数据类型。
- 一致性:抽象数据类型的实现应该保证接口定义的操作的行为和语义是一致的,不会因为不同的实现方式而导致不同的结果或副作用。
- 可替换性:抽象数据类型的实现应该可以被其他的实现替换,而不影响用户程序的功能和正确性。
实例:
抽象数据类型的实现可以有多种方式,比如用数组、链表、树、哈希表等不同的数据结构来存储和组织数据,用循环、递归、分治等不同的算法来执行操作。
形式定义
抽象数据类型可以用{D、S、P}三元组表示
- D是数据对象(data)
- S是D上的关系集(struct)
- P是对D的基本操作(prodecure)
ADT Name{
数据对象:D
数据关系:S
基本操作:P
} ADT Name