第一章 绪论

本文介绍了数据结构的基础概念,包括数据元素、逻辑结构(集合、线性结构、树形结构、图形结构)、存储结构(顺序存储、链式存储、哈希存储)以及抽象数据类型。同时,文章也涵盖了算法的基本特性和时间复杂度分析。
摘要由CSDN通过智能技术生成

数据结构复习第二天!!

目录

1.数据结构

1.1 数据结构的定义: 

1.2 逻辑结构

1.3 存储结构

顺序存储结构

链式存储结构

哈希存储结构

1.4抽象数据类型


1.数据结构

1.1 数据结构的定义: 

数据:是描述客观事物的数和字符的集合。

数据项:数据结构中的基本单位,是数据的最小单元。一个数据项可以是一个简单的数据类型,例如整数、字符、布尔值等,也可以是一个复杂的数据类型,例如数组、结构体、类等。

数据对象:是指性质相同的数据元素的集合。

数据结构:指所有数据元素以及数据元素之间的关系,数据结构的定义通常包括两个方面:数据元素和数据元素之间的关系。

1.2 逻辑结构

1、数据的逻辑结构是从数据元素的逻辑关系上描述数据的。常用二元组来表示数据的逻辑结构:

B=(D,R)

D=\left \{ d_{i}\mid1\le i\le n,n\ge 0 \right \}

R=\left \{ r_{j}\mid1\le i\le m,m\ge 0 \right \}

B是一种数据逻辑结构,由 D 数据元素的集合还有 R 数据元素之间的关系的集合组成。角标 i 代表 D 中的第 i 个数据元素,j 代表集合 R 中的第 j 个关系。

2、逻辑结构的类型

在计算机科学中,数据的逻辑结构是指数据元素之间的逻辑关系,通常可以分为以下四种基本类型:集合线性结构树形结构图形结构

  • 集合:集合是一个不包含重复元素的无序数据结构,数据元素之间除了属于同一个集合之外没有其他关系
  • 线性结构:线性结构是一种最基本的逻辑结构,它的数据元素之间存在一对一的关系。线性结构可以分为两种类型:线性表和栈和队列。
  • 树形结构:树形结构是一种非线性结构,它的数据元素之间存在一对多的关系。树形结构由若干个结点组成,结点之间通过边连接。其中,一个结点被称为根节点,它没有父结点;其他结点都有且只有一个父结点。树形结构具有层次性和分支性,可以分为多个子树。

  • 图形结构:图形结构是一种非线性结构,它的数据元素之间存在多对多的关系。图形结构由若干个结点和连接这些结点的边组成。图形结构可以分为有向图和无向图两种类型。在有向图中,边有方向,连接两个结点的边只能从一个结点指向另一个结点;在无向图中,边没有方向,连接两个结点的边可以相互指向。

1.3 存储结构

顺序存储结构

顺序存储结构是采用一组连续的存储单元存放所有的数据元素,两个逻辑上相邻的元素在存储位置上也是相邻的。

链式存储结构

所有的结点地址不一定是连续的,在链表中,数据元素按照顺序存储在不同的内存块中,每个内存块包含一个数据域和一个指针域,指向下一个内存块的位置。

链表中的第一个内存块称为头结点,最后一个内存块称为尾结点,尾结点的指针域为空。可以通过头结点的指针来访问整个链表。链式存储结构可以动态地分配和释放内存,可以灵活地处理不同大小和类型的数据元素,因此在实际应用中得到广泛的应用。

哈希存储结构

哈希表存储结构:将数据元素存储在哈希表中,每个元素根据哈希函数的值存储在对应的槽中。可以支持快速的查找、插入和删除操作,但是需要处理哈希冲突的情况,效率受哈希函数的质量和数据规模的影响。

1.4抽象数据类型

抽象数据类型(ADT)是指一种数据类型的抽象描述,它定义了数据类型的逻辑特征,包括数据对象、数据关系和对数据的操作。ADT的实现细节是隐藏的,只暴露出对外提供的接口,因此ADT是一种数据类型的抽象描述,与具体实现无关

ADT由三个方面组成:数据对象数据关系操作集合。数据对象是指数据类型的实例,数据关系是指数据对象之间的关系,操作集合是指对数据对象的操作。

用一个三元组表示 (D,S,P) ,D 是数据对象,S是数据关系,P是操作集合。使用 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 算法效率的度量

度量一个程序的执行时间通常有两种方法:

  1. 事后统计的方法
  2. 事前分析估算的方法

一般来说,算法中基本操作的重复执行的次数是问题规模n的某个函数 f(n) 

算法的时间度量记作  T(n)=O(f(n))  随着问题规模n的增大,算法执行时间的增长率和 f(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表示,取频度的数量级。

时间复杂度的关系O(1)<O(log_{2}n)<O(n)<O(nlog_{2}n)<O(n^{2})<O(n^{3})<O(2^{n})<O(n!)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值