数据结构

数据结构的三要素

算法设计依赖于数据的逻辑结构
算法实现依赖于数据的存储结构

  1. 逻辑结构
    指数据元素之间的逻辑关系,即从逻辑关系上描述数据。它与数据的具体存储形式无关,是独立于计算机的。数据逻辑结构通常分为线性结构非线性结构
    典型的数据结构与其逻辑结构的对应关系如下:
  • 集合结构:数据元素之间只存在 “同属于一个集合”的关系。
  • 线性结构:数据元素之间只存在“一对一”的关系。
  • 树形结构:数据元素之间存在“一对多”的关系。
  • 图状结构或网状结构:数据元素之间存在“多对多”的关系。
  1. 物理结构
    数据结构在计算机中的表示,也称为存储结构,又称映像
    它包括数据元素的表示和关系的表示。数据存储结构依赖于计算机语言,它是用计算机语言实现的逻辑结构。
    数据的线性存储结构主要有:顺序存储链式存储、索引存储、散列存储。
    顺序存储:把逻辑上相邻的数据元素存储在物理位置也相邻的存储单元里,元素之间的关系由存储单元之间的位置关系,即相邻关系来体现。如顺序表。
  • 优点:容易实现随机存取,每个元素占用最少的存储空间。
  • 缺点:只能使用相邻的一整块存储空间,容易产生较多的外部内存碎片。

链式存储:使用表示元素存储地址的指针来表示元素之间的逻辑关系,此时不要求逻辑上相邻的数据元素在物理位置上也相邻。如单链表

  • 优点:不会出现碎片内存,能充分利用存储单元。
  • 缺点:每个元素由于存储指针而占用额外的存储空间,且只能通过遍历实现顺序存取。

索引存储:在存储数据元素的同时,建立一个附加的索引表。索引表中的每一项称为索引项项,其形式通常为(关键字,地址)。

  • 优点:检索速度快。
  • 缺点:附加的索引表会占用额外的存储空间。在添加或者删除数据元素时,需要同步修改索引表,因此会花费额外的时间。

散列存储:根据元素的关键字以某种方式计算出该元素的存储地址,又称为 hash 存储。如哈希表。

  • 优点:检索、添加、删除的操作速度都很快。
  • 如果散列函数(或者 hash 函数)设计不好的话,可能会出现 hash 冲突,解决冲突又会增加时间和空间开销。
  • 而数据的非线性存储结构主要有:树形存储、图形存储。
  • 树是图的特例,树是连通的无回路的无向图
  • 线性表是树的特例,线性表是单枝树
  1. 数据运算:
  • 数据的运算主要体现为运算的定义,以及运算的实现。
  • 运算的定义是针对数据逻辑结构的,它描述了运算所能实现的功能。
  • 运算的实现是针对数据存储结构的,它描述了运算的具体操作过程。

程序 = 数据结构+算法

算法的五大特性

(1)有穷性:
一个算法必须总是在执行有穷步后结束,且每一步都必须在有穷时间内完成。

(2) 确定性:
对千每种情况下所应执行的操作,在算法中都有确切的规定,不会产生二义性, 使算法的执行者或阅读者都能明确其含义及如何执行。

(3) 可行性:
算法中的所有操作都可以通过已经实现的基本操作运算执行有限次来实现。

(4) 输入(0,*):
一个算法有零个或多个输入。当用函数描述算法时,输入往往是通过形参表示的, 在它们被调用时,从主调函数获得输入值。

(5) 输出(1,*):
一个算法有一个或多个输出,它们是算法进行信息加工后得到的结果,无输出的 算法没有任何意义。
当用函数描述算法时,输出多用返回值或引用类型的形参表示。

"好"算法的特质

(1)正确性:能正确解决问题
(2)可读性:对算法的描述要让其他人也看得懂
(3)健壮性:能处理一些异常
(4)高效率低存储量需求

线性表(Linear List)

线性表

  • 具有**相同(即每个数据元素所占空间一样大)元素类型的n(n≥0)个数据元素的有限**(有次序,有上限)序列

顺序表

  • 顺序存储的方式实现线性表
  • 顺序表在物理上是**连续的存储空间**

顺序表的特点

  • 随机访问(查找时间复杂度为O(1))
  • 存储密度高
  • 扩展容量不方便
  • 插入、删除数据元素不方便

链表

  • 链表是一种物理存储单元上**非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针**链接次序实现的
  • 链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时**动态生成**。
  • 每个结点包括两个部分:一个是存储数据元素的**数据域(data),另一个是存储下一个结点地址的指针域**(next)。
  • 链表在插入的时候可以达到O(1)的复杂度
  • 查找一个节点或者访问特定编号的节点则需要O(n)的时间

逻辑结构一对一
运算(后进先出

  • 基本运算:
  1. 初始化:InitStack(&s)
  2. 进栈:push(&s,e)
  3. 出栈:pop(&s,&e)
  4. 判空:StackEmpty(s)
  5. 取栈顶元素:GetTop(s)
  • 应用:
  1. 括号匹配
  2. 数值转换
  3. 判断回文
  4. 表达式求值
  5. 迷宫求解

存储结构

  • 顺序存储(顺序栈):
  1. 静态分配空间
  2. 动态分配空间
  • 链式存储(链栈):
  1. 带头结点
  2. 不带头结点

判断空栈base == top
判断栈满top-base == StackSize

二叉树

逻辑结构:一对多
运算:

  • 基本运算
  1. 初始化
  2. 遍历(先序、中序、后序)
  3. 删除子树
  4. 层次遍历
  • 应用
  1. 求表达式的值
  2. 哈夫曼编码
  3. 哈夫曼树

存储结构:

  • 顺序存储:适合满二叉树或者完全二叉树
  • 链式存储:二叉链表、三叉链表、线索二叉树(先序、中序、后序)

性质:

  • 第i层最多结点数:2^(i-1) 2的i-1次方
  • 深度为k至多的结点数:2^k-1 2的k次方减一
  • n^0 = n^2+1 (度为0的结点数是度为2的结点数+1)
  • n个结点完全二叉树的深度(log以2为底向下取整+1)
  • 完全二叉树的编号,父亲与孩子的关系
  1. i结点的左孩子为2i,右孩子为2i+1
  2. i结点的父节点为i/2

程序设计语言的控制成分包括三种基本的控制构造:顺序结构选择结构循环结构

汇编程序Assembler是从汇编语言导机器语言的翻译程序;汇编程序属于系统软件

编译程序Compiler是从高级语言到及其语言的翻译程序;编译程序也是属于系统软件

机器语言是所有程序设计类语言中运行速度最快的,由于其不需要进行翻译,所以在执行速度上比高级语言快很多。

在可移植性方便,高级语言要优于机器语言,高级语言的跨平台性要强于机器语言。

汇编语言不可以被直接执行,需要翻译为机器语言才能执行

机器语言,使用二进制代码形式编写,可以被计算机直接执行。机器语言直接依赖机器的指令系统,不同类型甚至不同型号的计算机,其机器语言是不同的。机器语言不易记忆和理解,所编写的程序也难于修改和维护。

翻译程序中的编译方式最后是产生目标程序的。

机器语言直接依赖机器的指令系统,不同类型甚至不同型号的计算机,其机器语言是不同的,所以用机器语言编制的程序,不可能在不同类型的计算机上运行。

程序员可以根据程序中的需要,在原有程序的基础上定义新的数据类型,Java程序设计中最典型的是引用类型,程序员可以按需自行定义。C语言中可以定义结构体作为变量类型。

解释程序:按源程序中语句的执行顺序,逐条翻译并立即执行相应的功能的处理顺序,解释不产生目标程序。

编译程序∶将程序从高级语言转换到机器语言或汇编语言的翻译程序;

编译产生目标程序,目标程序可反复被执行,运行效率高。

逻辑运算也称为布尔运算,主要有(AND)、或(OR)、(NOT),常用的逻辑运算符有:

①OR 或 ||,比如两个中只要有一个成立,则结果就成立

②AND与 &&,比如两个中两个同时成立,则结果成立,否则不成立

③NOT或 !就是取反之意。

Java是面向对象的、用于网络环境编程的程序设计语言。其可移植性非常好,与使用任何操作系统无关,具有平台独立性、安全性和稳定性。

高级语言程序需要编译或解释之后才能被计算机识别和执行

运行效率:机器>汇编>高级

高级语言程序比机器或汇编的程序有更好的移植性

机器语言和汇编语言并没有退出历史舞台,指是很少直接去编写这些评语言的程序。

程序设计语言基本三要素:

(1)语法:表示构成语言的各个记号之间的组合规律

(2)语义:表示程序的各个语法成分含义。语义是程序语言中按语法规则构成的各个语法成分 的含义,可分为静态语义和动态语义。

(3)语用:程序与使用者之间关系,与运行环境和编译环境有很大关系。

程序设计语言的四大成分:

(1)数据成分:程序中所涉及的数据部分(变量、数组、结构体等即,数据名、数据类型、数 据结构等)

(2)运算成分:程序中所包括的运算部分(算术运算、逻辑运算、关系运算等)

(3)控制成分:程序中控制构造(顺序结构、选择结构、循环结构等)

(4)传输成分:程序中数据的传输(数据交换[赋值语句]、拷贝(strcpy、memcpy)、I/O操 作(输入输出库函数调用)、函数传参与返回等)

程序的控制结构:

(1)顺序控制结构:最基本、最普通的结构形式,按照程序中的语句行的先后顺序逐条执行。

(2)选择控制结构:单分支选择(if)、双分支选择(if…else)、多分支持(if… elseif…/switch…case)

(3)循环控制结构:for、do-while(最少被执行一次)、while

程序设计语言处理

(1)源程序:使用高级语言和汇编语言编写的程序称为源程序。

(2)目标程序:源程序—>翻译程序—>目标程序

(3)翻译程序:将某一种语言翻译成另一种语言

①、汇编程序:汇编语言的翻译程序,属于系统软件

②、高级语言的翻译程序:解释程序和编译程序,也属于系统软件

解释程序

(1)解释:解释器直接解释并且执行源语言程序,不产生目标程序(相当于“口译”)

(2)解释程序.按源程序中语句的执行顺序,逐条翻译并立即执行相应的功能的处理顺序,解 释不产生目标程序。

(3)算法简单,灵活,便于查错,占用内存少,运行效率低。

(4)适用于调试程序、交互程序等。

(5)解释型语言:BASIC、Visual Basic、VBScript、Java、JavaScript、PHP、Python等。

编译程序

(1)编译:把源程序编译为机器语言目标程序后,再由计算机运行。(相当于“笔译”)

(2)编译程序∶将程序从高级语言转换到机器语言或汇编语言的翻译程序。

(3)编译产生目标程序,目标程序可反复被执行,运行效率高。

(4)适用于翻译规模大、结构复杂、运行时间长的大型应用程序。

(5)编译程序的处理过程:编辑 ->编译 ->链接->运行

(6)编译型语言:C、C++、C#等。

源程序经过编译后产生目标文件,再经过链接之后生成可执行文件

算法的表示可以有多种形式,如文字说明(自然语言)、流程图表示、伪代码(一种介于自然语言和程序设计语言之间的文字和符号表达工具)和程序设计语言等。

算法的设计一般采用由粗到细、由抽象到具体的逐步求精的方法。

算法的必要满足条件

①、确定性:算法的每一条指令必须有确切的定义,无二义性。

②、有穷性:是指算法必须在有限的时间内做完,即算法必须能在执行有限个步骤之后终止。

③、可行性:算法中的描述在计算机中能执行,且在有穷时间内完成。

④、至少有一个(1个或多个)输出,但是可以没有(0个或多个)输入

解决问题的算法有很多,可以使用多种语言求解同一问题,那问题的结果必相同,否则算法就不能满足相关条件

算法是问题求解规则的一种过程描述,可以没有输入,但一定得有输出。

算法的设计一般采用由粗到细、由抽象到具体的逐步求精的方法。

数据结构中数据的逻辑结构分为线性结构和非线性结构。

二叉树、森林、图都是非线性的逻辑结构。

数据处理的效率与数据的逻辑结构和存储结构均相关。

数据的逻辑结构与数据的存储无关。

程序=算法+数据结构(是由科学家尼克劳斯-沃思提出)。

研究数据结构一般包括三方面:

数据的逻辑结构、

数据的存储结构,

定义在逻辑结构和存储结构上的运算。

算法和程序的区别

算法:可以没有输入,但是必有一个输出

程序:可以没有输入,也可以没有输出

算法的表示(描述)工具:流程图、自然语言、伪代码、程序设计语言。

程序可以被计算机执行。

算法不能被计算机直接执行,需要使用程序设计语言实现,编译或解释。

顺序查找,对线性表不做有序要求,效率最低。

折半查找(二分查找)效率最高,需要线性线有序,非动态。

分块查找效率居中,需要有序,且最好为动态的,是顺序和折半的一种改装算法。

数据的逻辑结构常见的结构:集合、线性、树状、网状等。

数据的物理结构常见的存储结构:顺序,链接,索引等;

算法的表示不一定能让计算机理解。程序才是需要被计算机理解的。

图是网状结构,存在多对多节点连接,地图规则可能 会涉及多个地点与多个地点之间的连接。

队列是指允许在一端进行插入、而在另一端进行删除的线性表。它又称为"先进先出"或"后进后出"的线性表,体现了"先来先服务"的原则。

数据的逻辑结构在计算机存储空间中的存放形式称为数据的存储结构(也称数据的物理结构)

一般来说,一种数据的逻辑结构根据需要可以表示成多种存储结构,常用的存储结构有顺序、链接、索引等存储结构。而采用不同的存储结构,其数据处理的效率是不同的。

正确性和算法的复杂度是优先考虑的,其次才会考虑是否可读性、是否健壮性、是否容易调试和测试等。

栈和队列都属于线性结构(线性表、字符串、数组以及广义表也属于),栈的特点是后进先出,而队列属于先进先出