• 第二节--常用数据结构


    第二节–常用数据结构

    一.认识数据结构

    计算机具有处理速度快和存储容量大的两大特点

    所谓数据(Data),指的就是一种未经处理的原始文字(Word),数字(Number),符号(Symbol)或图形(Graph)等。我们可将数据分为两大类:一类为数值数据(Numeric Data),例如0,1,2,3…9等所组成可用运算符(Operator)来进行运算的数据;另一类为字符数据(Alphanumeric Data),像A,B,C…+,*等非数值数据(Non-Numeric Data)

    信息(Information)就是利用大量的数据,经过有系统的整理,分析,筛选处理而提炼出来的,而且具有参考价格以及提供决策依据的文字,数字,符号或图表

    数据结构主要是表示数据在计算机内存中所存储的位置及其模式,通常可以分为以下三种类型:

    1. 基本数据类型(Primitive Data Type)—不能以其他类型来定义的数据类型,或称为标量数据类型(Scalar Data Type)
    2. 结构化数据类型(Structured Data Type)—结构数据类型也称为虚拟数据类型(Virtual Data Type),是一种比基本数据类型更高一级的数据类型,例如:字符串(string),数组(array),指针(pointer),列表(list)等
    3. 抽象数据类型(Abstract Data Type ,ADT)

    二.数据结构的种类

    1.数组

    “数组”(Array)结构其实就是一排紧密相邻的可数内存,并提供了一个能够直接访问单一数据内容的计算方法

    1.1二维数组
    二维数组(Two-dimension Array)可视为一维数组的扩展,都是用于处理数据类型相同的数据,差别只在于维数的声明。

    在python语言中,列表中可以有列表,这种情况就称为二维列表,要读取二维列表的数据可以通过for循环。二维列表简单来讲是列表中的元素也是列表。下面举例来说明:

    number = [[11,12,13],[22,24,26],[33,35,37]]    
    

    1.2三维数组
    三维数组(Three-dimension Array),基本上三维数组的表示法和二维数组一样,都可视为一维数组的延伸,如果数组为三维数组,可以看作是一个立方体
    将arr[2][3][4]三维数组想象成空间上的立方体。python中声明三维数组:

    arr = [[[33,4,6,12],[23,71,6,15],[55,38,6,18]],[[21,9,15,21],[38,69,18,26],[90,101,89,16]]]
    

    2.链表

    链表(Linked List)是由许多相同数据类型的数据项按特定顺序排列而成的线性表。链表的特点是各个数据项在计算机内存中位置时不连续且随机(Random)存放的,其优点是数据的插入或删除都相当方便。其缺点就是设计数据结构较为麻烦,并且在查找数据时,也无法像静态数据(如数组)那样可随机读取数据,必须按序查找到该数据为止

    在动态分配内存空间时,最常使用的就是"单向链表"(Single Linked List)。一个单向链表节点基本上是由数据字段和指针两个元素组成的,指针将会指向下一个元素在内存中的地址

    在"单向链表"中第一个节点是"链表头指针",指向最后一个节点的指针设为None,表示它是"链表尾",不指向任何地方。例如,列表A={a,b,c,d,x},其单向链表的数据结构如下图;
    未命名文件.png

    3.堆栈

    堆栈(Stack)是一种相同数据类型的组合,具有"后进先出"(Last In First Out,LIFO)的特性,所有的操作均在堆栈结构的顶端进行

    堆栈是一种抽象型数据结构(Abstract Data Type,ADT),具有下列特性:

    1. 只能从堆栈的顶端存取数据
    2. 数据的存取符合"后进先出"的原则

    4.队列

    队列是一种"先进先出"(First In First Out)的数据结构,和堆栈一样都是一种有序线性表的抽象数据类型(ADT)

    堆栈只需一个顶端(Top),指针指向堆栈顶端,二队列则必须使用front和rear两个指针分别指向队列前端和队列尾端

    三.树形结构

    1.树的基本观念

    “树”(Tree)是由一个或一个以上的节点(Node)所组成的,存在一个特殊的节点,称为树根(Root),每个节点可代表一些数据和指针组合而成的记录。其余节点则可分为n>=0个互斥的集合,即(T1,T2,T3…Tn),每一个子集合本身也是一种树形结构及此根节点的子树

    在树形结构中,有许多常用的专有名词:

    • 度数(Degree):每个节点所有子树的个数。例如:图1中的节点B的度数为2,D的度数为3,F,K,I,J等的度数为0
    • 层数(level):树的层数,假设树根A为第一层,B,C,D节点的层数为2,E,F,G,H,I,J的层数为3
    • 高度(Height):树的最大层数。图1所示的树的高度为4
    • 树叶或称终端节点(Terminal Nodes):度数为零的节点就是树叶。图1中的K,L,F,G,M,I,J就是树叶,图2则有4个树叶节点,如E,C,H,I

    未命名文件 (1).png

    2.二叉树

    一般树形结构在计算机内存中的存储方式是以链表(Linked List)为主。对于n叉树(n-way树)来说,因为每个节点的度数都不相同,所以我们必须为每个节点都预留存放n个链接字段的最大存储空间,因而每个节点的数据结构如下:
    未命名文件 (2).png

    请大家特别注意,这种n叉树十分浪费链接存储空间。假设此n叉树有m个节点,那么此树共有nm个链接字段。另外,因为除了树根外,每一个非空链接都指向一个节点,所以得知空链接个数为nm-(m-1),而n叉树的连接浪费率为m*(n-1)+1/m*n。因此我们可以得到以下结论:

    • n=2时,二叉树的链接浪费率约为1/2
    • n=3时,三叉树的链接浪费率约为2/3
    • n=4时,四叉树的链接浪费率约为3/4


    当n=2时,它的链接浪费率最低,所以为了改进存储空间浪费的缺点,我们最常使用二叉树(Binary Tree)结构来取代其他树形结构

    二叉树(又称为Knuth树)是一个由有限节点所组成的集合,此集合可以为空集合,或由一个数根及其左右两个子树所组成。简单来说,二叉树最多只能有两个子节点,就是度数小于或等于2。其计算机中的数据结构如下:
    未命名文件.png

    二叉树和一般树的不同如下:

    1. 树不可为空集合,但是二叉树可以
    2. 树的度数为d>=0,但二叉树的节点度数为0<=d<=2
    3. 树的子树间没有次序关系,二叉树则有

    四.图形结构简介

    树形结构用于描述节点与节点之间"层次"的关系,但是图形结构却是讨论两个顶点之间"连通是否"的关系,在图中连接两顶点的边若填上加权值,这类图就称为"网络"

    说到图形理论,就必须说说"七桥问题",欧拉思考问题如下"是否有人在只经过每一座桥梁一次的情况下,把所有的地方都走过一次而且回到原点"

    欧拉使用的方法就是以图形结构进行分析。他先以顶点表示城市,以边表示桥梁,并定义了连接每个顶点的边数为该顶点的度数。如上图右下图

    结论:当所有顶点的度数都为偶数时,才能从某顶点出发,经过每条边一次,在回到起点。也就是说图中都为奇数,所以欧拉所思老的问题是不可能发生的,这个理论就是有名的"欧拉环"(Eulerian Cycle)理论

    如果条件改成从某顶点出发,经过每条边一次,不一定要回到起点,即只允许其中两个顶点的度数是奇数,其余则必须全部为偶数,符合这样的结果就称为欧拉链(Eulerian Chain)。如下图
    未命名文件 (1).png

    图形的定义

    图是由"顶点"和"边"所组成的集合,通常用G=(V,E)来表示,其中V是所有顶点所组成的集合,而E代表所有边所组成的集合。图的种类有两种:一种是无向图,一种有向图,无向图以(V1,V2)表示其边,而有向图则以<V1,V2>表示其边

    1.无向图

    无向图(Graph)是一种边没有方向的图,即同边的两个顶点没有次序关系,例如(V1,V2)与(V2,V1)代表的是相同的边,如下图
    未命名文件 (2).png

    V={A,B,C,D,E}
    E={(A,B),(A,E),(B,C),(B,D),(C,D),(C,E),(D,E)}
    

    2.有向图

    有向图(Digraph)是一种每一条边都可使用有序对<V1,V2>来表示的图,所谓的<V1,V2>是指V1为尾端指向为头部的V2
    未命名文件 (3).png

    V={A,B,C,D,E}
    E={<A,B>,<B,C>,<C,D>,<C,E>,<E,D>,<D,B>}
    

    五.哈希表

    哈希表是一种存储记录的连续内存,通过哈希函数的应用,可以快速存取与查找数据。基本上,所谓哈希法(Hashing)就是将本身的键值,通过特定的数学函数运算或使用其他的方法,转换成相对应的数据存储地址

    哈希函数的相关名词:

    • bucket(桶):哈希表中存储数据的位置,每一个位置对应到唯一的一个地址(bucket address)。桶就好比一个记录
    • slot(槽):每一个记录中可能包含好几个字段,而slot指的就是"桶"中的字段
    • collision(碰撞):两项不同的数据,经过哈希函数运算后,对应到相同的地址
    • 溢出:如果数据经过哈希函数运算后,所对应到的bucket已满,就会使bucket发生溢出
    • 哈希表:存储记录的连续内存。哈希表是一种类似数据表的索引表格,可分为n个bucket,每个bucket又可分为m个slot
    • 加载密度(Loading Factor):所谓加载密度是指标识符的使用数量除以哈希表内槽的总数。@(加载密度)=n(标识符的使用数目)/[s(每一个桶内的槽数)*b(桶的数目)]。@值越大,表示哈希空间的利用率越高,碰撞或溢出的概率也会越高
    • 完美哈希(Perfect Hashing):没有碰撞也没有溢出的哈希函数

    未命名文件.png
    通常在设计哈希函数时应该遵循以下几个原则:

    1. 降低碰撞和溢出的产生
    2. 哈希函数不宜过于复杂,越容易计算越佳
    3. 尽量把文字的键值转换成数字的键值,以利于哈希函数的运算
    4. 所设计的哈希函数计算得到的值,尽量能均匀地分布在每一个桶中,不要太过于集中在某些桶内,这样就可以降低碰撞,并减少溢出的处理
  • 相关阅读:
    Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(六)之Initialization & Cleanup
    ValidForm.js的使用注意点
    我的第一个敏捷项目总结
    七月在线机器学习项目
    吴恩达机器学习
    emoji情感分类器
    序列模型实践工程
    序列模型-NLP和词嵌入
    吴恩达深度学习
    序列模型
  • 原文地址:https://www.cnblogs.com/LQ6H/p/10346669.html
Copyright © 2020-2023  润新知