数据结构学习

数据结构的基本概念

数据结构是相互之间存在一种或者多种特定关系的数据元素的集合。

数据结构包括逻辑结构和存储结构两个层次

逻辑结构分为四种类型:集合结构,线性结构,树形结构,图形结构。、

物理结构又叫存储结构,分为两种,顺序存储结构、链式存储结构。

逻辑结构

集合结构:数据元素同属一个集合,单个数据元素之间没有任何关系。

线性结构:类似于线性关系,线性结构中的数据元素之间是一对一的关系。

树形结构:树形结构中的数据元素之间存在一对多的关系。(各元素及元素关系所组成图形头似于树状图)。

图形结构:数据元素之间是多对多的关系。

存储结构

顺序存储结构是把数据元素放到地址连续的存储单元里面,其数据间的逻辑关系和物理关系是
致的。之前学习的数组就是一种顺序存储结构。

链式存储结构:是把数据元素存放在任意的存储单元里面,这组存储单元可以是连续的也可以
是不连续的

数据类型和抽象数据类型

a、数据类型:一个值的集合及定义在这个值集上的一组操作的总称。
一般包括整型、实型、字符型等原子类型外,还有数组、结构体和指针等结构类型
b、抽象数据类型
抽象数据类型(Abstract Data Type,ADT),类似C语言中的结构体以及C++语言中的类。
通俗的讲,抽象数据类型,泛指除基本数据类型以外的数据类型

算法 (algorithm)是对特定问题求解步骤的一种描述,它是指令的有限序列,其中每一条指令表示一个或多个操作;此外,一个算法还具有下列5个重要特性:
1.有穷性:一个算法必须总是(对合法的输入值)在执行有穷步之后结束,且每一步都可在有穷时间内完成。
2.确定性:算法中每一条指令必须有确切的含义,读者理解时不会产生二义性。并且,在任何条件下,算法只有惟一的一条执行路径,即对于相同的输入只能得出相同的输出。
3.可行性:一个算法是能行的,即算法中描述的操作都是可以通过已经实现的基本运算执行有限次来实现的
4.输入:一个算法有零个或多个的输入,这些输入取自于某个特定的对象的集合。
5.输出:一个算法有一个或多个的输出,这些输出是同输入有着某些特定关系的量。

算法+数据结构=程序

算法设计的要求:

1.正确性
2.可读性
3.健壮性
4.高效性与低存储量

时间复杂度指算法中各语句执行时间的总和

for (i=1;i<=n;++i)//执行n+1次
    for (j=1;j<=n;++j)//执行n(n+1)次
        x=x+1;//执行n2次
语句执行次数:f(n)=2n^2+2n+1
算法的执行时间:T(n)=O(n^2)

1.最好时间复杂度,指的是算法计算量可能达到的最小值。
2.最坏时间复杂度,指的是算法计算量可能达到的最大值。
3.平均时间复杂度,是指算法在所有可能情况下,按照输入实例以等概率出现时,算法计算量的加权平均值。

算法的时间复杂度不仅与问题的规模有关,还与问题的其他因素有关。如某些排序的算法,其执行时间与待排序记录的初始状态有关为此,有时会对算法有最好、最坏以及平均时间复杂度的评价。

空间复杂度只需要分析辅助变量所占的额外空间。
空间复杂度:S(n)=O(f(n))
如果算法执行所需要的临时空间不随着某个变量n的大小而变化,即此算法空间复杂度为一个常量,可表示为 O(1)。

总结

简述下列概念:数据、抽象数据类型、数据元素、数据项、数据对象、数据结构、逻辑结构、存储结构。
数据:是客观事物的符号表示,指所有能输入到计算机中并被计算机程序处理的符号的总称
数据元素:是数据的基本单位,在计算机中通常作为一个整体进行考虑和处理。在有些情况下,数据元素也称为元素、结点、记录等。
数据项:是组成数据元素的、有独立含义的、不可分割的最小单位。
数据对象:是性质相同的数据元素的集合,是数据的一个子集。
数据结构:是相互之间存在一种或多种特定关系的数据元素的集合。
逻辑结构:从逻辑关系上描述数据,它与数据的存储无关,是独立于计算机的。
存储结构:数据对象在计算机中的存储表示,也称为物理结构。
抽象数据类型:由用户定义的,表示应用问题的数学模型,以及定义在这个模型上的一组操作的总称。具体包括三部分:数据对象、数据对象上关系的集合和对数据对象的基本操作的集合。

线性表的定义

由n(n>=20)个数据特性相同的元素构成的有限序列称为线性表,(n=0)的时候被称为空表。
一个数据元素可以是简单的一个数据,一个符号,也可以是复杂的若干个数据项的组合

线性表的特点

线性结构特点:在数据元素的非空有限集中
存在唯一的一个被称作“第一个”的数据元素
存在唯一的一个被称作“最后一个”的数据元素
除第一个外,集合中的每个数据元素均只有一个前驱
除最后一个外,集合中的每个数据元素均只有一个后继

线性表的优缺点

优点:逻辑相邻,物理相邻:存储空间使用紧凑,不必为结点间的逻辑关系而增加额外的存储开销

可随机存取任一元素

方法简单,各高级语言使用数组来实现,python的列表也引用的是数组结构。

缺点:插入、删除操作需要移动大约表中一半的元素对n较大的顺序表效率低。

结论:在顺序表中插入或删除一个元素时,平均移动表的一半元素,当n很大时,效率很低。

顺序表只能存相同类型数据。

线性表的实现

顺序存储

线性表的顺序存储又被称为顺序表。
顺序存储表示:用一组地址连续的存储单元依次存储线性表的数据元素的方式,具有顺序存储结构的特点(数据间的逻辑关系和物理关系是一致的)
假设线性表L存储的起始位置为 LOC(A),sizeof(ElemType)是每个数据元素所占用存储空间的大小,则表L所对应的顺序存储如下图:

线性表的顺序存储结构是一种随机存取的存储结构,即通过首地址和元素序号为以在0(1)时间内找到指定的元素。由于线性表的长度可变,且所需最大存储空间随问题的不同而不同,在C/C++语言中通常使用动态分配的一维数组表示线性表。

线性表的链式实现

链式存储结构的特点:用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的),存放数据元素的结点至少包括两个域(指针域、数据域D也可以包含若于个指针域和数据域)。双向链表和单向链表。

数据域:数据元素本身信息

链接域(指针域):直接后继或直接前驱的存储地址

线性链表的分类:

单链表:每个结点除包含有数据域外,只设置一个链接域,用以指向其后继结点。 

class Node(object):
    def __init__(self,data):
        self.data = data
        self.next = None
单链表的特点:

1.它是一种动态结构,整个内存空间为多个链表共用
2.不需要预先分配空间
3.链接域占用额外存储空间
4.不能随机存取,查找速度慢,存储率低

单链表的操作

1) 判断单链表是否为空,判断head是否为空

2) 头插法插入元素时间复杂度为O(1)。尾插法插入元素时间负责度为O(n)

3) 对链表中的n个元素扫描一遍,时间复杂度为O(n)

4) 性能分析:对链表中的个元素扫描一遍,时间复杂度为O(n)

6) 单链表取值算法的平均时间复杂度为 O(n)

7) 在指定位置插入元素

8)按值删除元素

双向链表:

每个结点除包含数据域外,设置两个链接域,分别用以指向其前驱结点和后继结点

关于带头结点的单链表及不带头节点的单链表
首元结点:是指链表中存储第一个数据元素的结点。
头结点:是在首元素结点之前附设的一个结点,其指针指向首元结点。
头指针:是指向链表中第一个结点的指针。若链表设有头结点,则头指针所指结点为线性表的头结点;若链表不设头结点,则头指针所指结点为该线性表的首元结点。

class DLNode(object):
    def __init__(self,data):
        self.data=data
        self.prior=None
        self.next=None

1) 双链表的在某个结点前插入结点p算法

s=DLNode(b):
s.prior=p.prior
p.prior.next=s
s.next=p
p.prior=s

2)双链表中删除结点p算法

p.prior.next=p.next
p.next.prior=p.prior

顺序表VS线性表

1.从空间上考虑
(1)当线性表的长度变化较大时,难以估计其存储规模,以采取动态链表作为存储结构为好。
(2)当线性表的长度变化不大时,为了提高存储密度,以采取顺序表作为存储结构。存储密度是指结点数据本身所占的存储量和整个结点结构所占的存储量之比。
2.从时间上考虑
(1)如果线性表的操作主要是进行按序号访问数据元素做插入、删除操作,采用顺序表为宜。
(2)对于频繁地进行插入和删除的线性表采用链表存储结构为宜。

习题讲解:

栈和队列的定义与特点

栈:受约束的线性表,只允诛栈顶元素入栈和出栈

对栈来说,表尾端称为栈顶,表头端称为栈底,不含元素的空表称为空栈先进后出,后进先出

栈顶(top)和栈底(bottom):允许插入、删除的一端称为栈顶另一端称为栈底。

空栈:表中没有元素称为空栈。添加元素:入栈、压栈push;删除元素:出栈pop

怎么判断栈是空的还是满的?

top 指栈顶元素后一位置、S.top == 0时,栈空、S.top==stacksize 时,栈满

顺序栈操作的实现:

栈的本质是线性表,线性表的存储结构对栈也适用,栈的顺序存储结构称为顺序栈,与顺序表类似,在python中使用列表来实现顺序栈,其他的语言使用数组来实现顺序栈。

入栈

出栈

栈的链式存储结构

称为链栈,它是运算受限的单链表插入和删除操作仅限制在表头位置上进行。

栈的应用

进制转换、括号匹配、表达式求值、函数的调用、函数的递归、八皇后问题、迷宫的求解

递归的定义:若一个对象部分地包含它自己,或用它自己定义自己则称这个对象是递归的。

递归函数:在定义的时候,自己调用了自己的函数。例如求n!

队列

队列:受约束的线性表,只允许在队尾插入,在队头删除。先进先出,后进后出

1.队列(Queue):运算受限的线性表。它只允许在表的一端进行插入,而在另一端进行删除。
2.队头(front)和队尾(rear):允许删除的一端称为队头,允许插入的一端称为队尾
3.队列的运算规则:先进先出

为什么要建立循环队列

在循环队列中进行出队/入队操作时,头尾指针仍要加1,向上移动。只不过当头/尾指针指向向量上界(M-1)时,其加1操作的结果是指向向量的下界0

循环队列的入出队以及堆满空的判断方法

链队列

限制仅在表头进行删除和表尾进行插入的单链表。一个链队列由一个头指针和尾指针唯一确定。

在循环队列的顺序存储结构中,除了用一组地址连续的存储单元依次存放从队列头到队列尾的元素之外尚需附设两个指针{front和rear 分别指示队列头元素及队列尾元素的位置。
为了在 C/C++语言中描述方便起见,在此我们约定:初始化建空队列时,令front=rear=0,每当插入新的队列尾元素时,“尾指针增 1";每当删除队列头元素时,“头指针增1”。因此,在非空队列中,头指针始终指向队列头元素,而尾指针始终指向队列尾元素的下一个位置,如图所示。

怎么判断队列是满还是空?

1.少用一元素空间,即队列空间大小为m时,有m-1个元素就认为是队满。这样判断队空的条件不变,即当头、尾指针的值相同时, 则认为队空;而当尾指针在循环意义上加1后是等于头指针, 则认为队满。

2.另设一个标志位以区别队列是“空”还是 “满。

总结:

栈是限定仅在表尾进行插入或删除的线性表,又称为后进先出的线性表。栈有两种存储表示,顺序表示(顺序栈和链式表示(链栈)。栈的主要操作是进栈和出栈,对于顺序栈的进栈和出栈操作要注意判断栈满或栈空。

队列是一种先进先出的线性表。它只允许在表的一端进行插入,而在另一端删除元素。队列也有两种存储表示顺序表示(循环队列)和链式表示(链队)

栈和队列的逻辑结构都和线性表一样,数据元素之间存在一对一的关系。

栈和队列是使用频率最高的数据结构。栈和队列是指插入和删除只能在表的一端进行的线性表

循环队列中少用一个元素判断队空或队满时:

队空的条件:Q.front == Q.rear
队满的条件:(Q.rear+ 1)%MAXQSIZE == Q.front

习题

串的定义和特点

串即字符串,是由零个或多个字符组成的有限序列,是数据元素为单个字符的特殊线性表。
串是内容受限的线性表,它限定了表中的元素为字符
串长:串中字符个数(n20):n=0 时称为空串
空白串:由一个或多个空格符组成的串
子串:串S中任意个连续的字符序列叫S的子串,S叫主串
当两个串的长度相等,并且各个对应位置的字符都相等时,才称这两个串相等

串的存储结构: 定长顺序存储、堆分配存储、块链存储

定长顺序存储:按照预定义的大小,为每个定义的串变量分配一个固定长度的存储区,通常用定长字符数组来实现。堆分配存储:仍以一组地址连续的存储单元存放串值,但存储空间是在程序执行过程中动态分配而得。串的块链存储:串采用链式存储结构存储时称为链串。链串中的一个结点可以存储多个字符。通常将链串中每个结点所存储的字符个数称为结点大小。

数组

数组是线性表的推广,特点是结构中的元素本身可以是具有某种结构的数据,但属于同一数据类型。

列表

总结

串是内容受限的线性表,它限定了表中的元素为字符。

多维数组可以看成是线性表的推广,其特点是结构中的元素本身可以是具有某种结构的数据,但属于同一数据类型。

广义表是另一种线性表的推广形式,表中的元素可以是称为原子的单个元素,也可以是一
子表,所以线性表可以看成广义表的特例。

习题

树是一种非线性的数据结构,它是由n个有限结点组成有层次关系的集合。

树具有以下特点,可以根据这些特点来判断一个数据结构是否是树
每个结点具有0个或多个子结点
每个子结点只有一个父结点
没有前驱的结为根结点
除了根结点外,每个子结点又可以由m棵不相关的子树组成

结点的度:结点拥有的子树数量称为结点的度

树的度:树内各结点度的最大值,即上图D结点的度就是此树的度


叶子:度为0的节点称为时子或终端节点
结点的层次和树的深度

结点的层次从根开始定义起,根为第一层,根的孩子为第二层,以此类推。树的深度(Depth)或高度是树中结点的最大层次。


森林:m棵互不相交的树的集合

二叉树

二叉树(Binary Tree)定义:二叉树是有限元素的集合,该集合或为空,或由一个称为根的元素及两个不相交、分别称为左子树和右子树的二叉树构成;左、右子树本身也是二叉树----递归定义。

二叉树的特点:

二叉树与树主要有以下区别:

二叉树每个结点至多只有两棵子树(即二又树中不能存在度大于 2 的结点
二叉树的子树有左右之分,其次序不能任意颠倒
即使树中某结点只有一棵子树,也要区分它是左子树还是右子树

二叉树的性质

对于非空二叉树,如果叶子结点数为n0,度为2的节点数为n2,则n0=n2+1

满二叉树:如果深度为k的二叉树有2^k-1个结点,则称为满二叉树。

特点:每一层上都含有最大节点数。

完全二叉树

如果二叉树除最后一层外每一层都是满的,且最后一层或者是满的,或者结点都连续地集中在该层的最左端,则称其为完全二叉树。特点:所有的叶子结点都出现在第k层或k-1层。

二叉树顺序存储

二叉树的顺序存储有很多缺点

二叉树的顺序存储一般是按照丛上至下、从左至右的顺序存储。但是,这样存储后结点在存储位置上的益驱、后继关系并不是它们在逻辑上的邻接关系,只有通过一些方法能够确定结点在逻辑上的前驱和后继结点,这种存储才有意义。

完全二叉树适合于采用顺序存储方式。

二叉树的链式存储

二叉树的链式存储更好

二叉链表:链表中每个结点包含三个域,数据域和两个指针域指针域分别用来指示该结点的左孩子和右孩子所在的结点的存储地址。

class BNode(object)
    def __init__(self,data=None,lchild=None,rchild=None):
        self.data=data
        self.lchild=lchild #左子树
        self.rchild=rchild #右子树

三叉链表:三叉链表中每个结点由4个域组成:数据域、双亲指针域左指针域、右指针域,双亲域为指向该结点双亲结点的指。

class Node:
    def __init__(self,data):
        self.lchild=None
        self.rchild=None
        self.parent=None
        self.data=data

二叉树的列表存储

列表是python的一种标准类型,二叉树结点是一个三元组;
二叉树是递归结构,python的列表也是递归结构;
python的元组也可以实现这种二叉树的递归结构,但是实现的是非变动性二叉树结构。

二叉树的遍历

二叉树的遍历:按某条搜索路径访问二叉树中每一个结点,使得每个结点被访问一次且仅被访问一次。遍历方法有4种:先序遍历,中序遍历,后序遍历,层次遍历。

先序遍历                                             中序遍历

后序遍历                                                       层序遍历

由遍历序列恢复二叉树

哈夫曼树

最优二叉树
假设有n个权值(w,,w.…w),构造有n个叶子结点的二叉树,每个叶子结点有一个w作为它的权值。则带权路径长度最小的二叉树称为哈夫曼树。

哈夫曼编码

哈夫曼编码(Hufman Coding),又称霍夫曼编码,是一种编码方式,可变字长编码(VLC)的一种。Huffman于1952年提出种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫做Huffman编码(有时也称为霍夫曼编码)。

如何使用哈夫曼编码来使得电文最短,而且不会出现二义性:
1)统计字符集中每个字符在电文中出现的概率,概率越大编码越短;
2)利用哈夫曼树的特点:权越大的叶子离根越近,将每个概率值作为权值,构造哈夫曼树。则概率越大的结点路径越短;
3)在哈夫曼树的每个结点的左分支标0,右分支标1;
4)从根到每个叶子的路径上标号链接起来,作为该叶子代表的字符的编码。

树和森林的概念

树是n(n>20)个结点的有限集合,在任一棵非空树中:
(1)有且仅有一个称为根的结点;
(2)其余结点可分为个互不相交的集合,而且这些集合中的每一集合都本身又是一棵树,称为根的子树。

森林:是m(m>=0)互不相交的树的集合。

习题

图的定义与基本术语

图的存储结构:邻接矩阵

图G由两个集合构成,记作G=<Y,E>,其中V(vertex)是顶点的非空有限集合,E(edge)是顶点间关系-边的有限集合,边是顶点的无序对或有序对集合。

连通图:无向图中任意两个顶点都是连通的图叫连通图

强连通图:有向图任意两个顶点都是连通的图叫连通

连通分量:无向图G的极大连通子图称为G的连通分量。“极大”的含义是:该子图是G连通子图,将G的任何不在该子图中的顶点加入,子图不再连通。

强连通分量:有向图的极大强连通子图称为强连通分量。

图的存储结构:邻接表

图的遍历

图的遍历:从图中某一顶点出发访遍图中其余结点,使每一个结点被访问且仅被访问一次
图的遍历通常有两种方法:深度优先搜索和广度优先搜索。它们对有向图和无向图都适用

深度优先搜索思想:

广度优先搜索

图的应用:拓扑排序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值