数据结构复习第二天!!
目录
1.数据结构
1.1 数据结构的定义:
数据:是描述客观事物的数和字符的集合。
数据项:数据结构中的基本单位,是数据的最小单元。一个数据项可以是一个简单的数据类型,例如整数、字符、布尔值等,也可以是一个复杂的数据类型,例如数组、结构体、类等。
数据对象:是指性质相同的数据元素的集合。
数据结构:指所有数据元素以及数据元素之间的关系,数据结构的定义通常包括两个方面:数据元素和数据元素之间的关系。
1.2 逻辑结构
1、数据的逻辑结构是从数据元素的逻辑关系上描述数据的。常用二元组来表示数据的逻辑结构:
B是一种数据逻辑结构,由 D 数据元素的集合还有 R 数据元素之间的关系的集合组成。角标 代表 D 中的第 个数据元素, 代表集合 R 中的第 个关系。
2、逻辑结构的类型
在计算机科学中,数据的逻辑结构是指数据元素之间的逻辑关系,通常可以分为以下四种基本类型:集合,线性结构、树形结构和图形结构。
- 集合:集合是一个不包含重复元素的无序数据结构,数据元素之间除了属于同一个集合之外没有其他关系
- 线性结构:线性结构是一种最基本的逻辑结构,它的数据元素之间存在一对一的关系。线性结构可以分为两种类型:线性表和栈和队列。
-
树形结构:树形结构是一种非线性结构,它的数据元素之间存在一对多的关系。树形结构由若干个结点组成,结点之间通过边连接。其中,一个结点被称为根节点,它没有父结点;其他结点都有且只有一个父结点。树形结构具有层次性和分支性,可以分为多个子树。
-
图形结构:图形结构是一种非线性结构,它的数据元素之间存在多对多的关系。图形结构由若干个结点和连接这些结点的边组成。图形结构可以分为有向图和无向图两种类型。在有向图中,边有方向,连接两个结点的边只能从一个结点指向另一个结点;在无向图中,边没有方向,连接两个结点的边可以相互指向。
1.3 存储结构
顺序存储结构
顺序存储结构是采用一组连续的存储单元存放所有的数据元素,两个逻辑上相邻的元素在存储位置上也是相邻的。
链式存储结构
所有的结点地址不一定是连续的,在链表中,数据元素按照顺序存储在不同的内存块中,每个内存块包含一个数据域和一个指针域,指向下一个内存块的位置。
链表中的第一个内存块称为头结点,最后一个内存块称为尾结点,尾结点的指针域为空。可以通过头结点的指针来访问整个链表。链式存储结构可以动态地分配和释放内存,可以灵活地处理不同大小和类型的数据元素,因此在实际应用中得到广泛的应用。
哈希存储结构
哈希表存储结构:将数据元素存储在哈希表中,每个元素根据哈希函数的值存储在对应的槽中。可以支持快速的查找、插入和删除操作,但是需要处理哈希冲突的情况,效率受哈希函数的质量和数据规模的影响。
1.4抽象数据类型
抽象数据类型(ADT)是指一种数据类型的抽象描述,它定义了数据类型的逻辑特征,包括数据对象、数据关系和对数据的操作。ADT的实现细节是隐藏的,只暴露出对外提供的接口,因此ADT是一种数据类型的抽象描述,与具体实现无关。
ADT由三个方面组成:数据对象、数据关系和操作集合。数据对象是指数据类型的实例,数据关系是指数据对象之间的关系,操作集合是指对数据对象的操作。
用一个三元组表示 , 是数据对象,是数据关系,是操作集合。使用 C++ 实现栈(Stack)抽象数据类型的例子
#include <iostream>
#include <vector>
using namespace std;
class Stack {
private:
vector<int> stack; // 存储栈中元素的 vector
public:
Stack() {} // 构造函数
void push(int x) {
stack.push_back(x); // 将元素 x 压入栈中
}
int pop() {
int x = stack.back(); // 取出栈顶元素
stack.pop_back(); // 弹出栈顶元素
return x;
}
int top() {
return stack.back(); // 返回栈顶元素
}
bool is_empty() {
return stack.empty(); // 判断栈是否为空
}
int size() {
return stack.size(); // 返回栈的大小
}
};
int main() {
Stack s; // 创建一个栈对象
s.push(1); // 将元素 1 压入栈中
s.push(2); // 将元素 2 压入栈中
s.push(3); // 将元素 3 压入栈中
while (!s.is_empty()) { // 循环弹出栈中元素并输出
cout << s.pop() << " ";
}
return 0;
}
2.算法和算法分析
2.1 算法
算法是指对特定问题求解步骤的一种描述,算法的五个重要特性:
- 有限性(Finiteness):算法必须在有限的步骤内执行结束,不会无限循环或永远运行下去。且每一步都是在有穷的时间内完成。
- 确定性(Definiteness):算法的每个步骤必须清晰明确,不会存在二义性或歧义。在任何条件下,算法只有唯一的一条执行路径,对相同的输入只能得到相同的输出。
- 可行性(Feasibility):算法必须是可行的,也就是说它可以通过一系列的基本操作来实现。
- 输入(Input):算法具有零个或多个输入
-
输出(Output):算法必须产生明确的输出结果,以解决给定的问题。输出可以是计算出的值、打印出的信息、存储在文件中的数据等,具体取决于算法所解决的问题。
算法的设计要求
- 正确性
- 可读性
- 健壮性
- 效率与低存储量需求
2.2 算法效率的度量
度量一个程序的执行时间通常有两种方法:
- 事后统计的方法
- 事前分析估算的方法
一般来说,算法中基本操作的重复执行的次数是问题规模n的某个函数
算法的时间度量记作 随着问题规模n的增大,算法执行时间的增长率和 的增长率相同,称作算法的渐进时间复杂度,简称时间复杂度
频度:指的是语句重复执行的次数
{
int a = 5;
int b = 10;
int sum = a + b;
}//频度为1
for (int i = 1; i <= n; i++) {
std::cout << i << " ";
}//频度为n
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
std::cout << i * j << " ";
}//频度为n²
我们习惯把频度用O表示,取频度的数量级。
时间复杂度的关系