第二节--常用数据结构

第二节–常用数据结构

一.认识数据结构

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

所谓数据(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. 所设计的哈希函数计算得到的值,尽量能均匀地分布在每一个桶中,不要太过于集中在某些桶内,这样就可以降低碰撞,并减少溢出的处理

转载于:https://www.cnblogs.com/LQ6H/p/10346669.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值