zoukankan      html  css  js  c++  java
  • 数据结构占坑

    前言

    先看这篇

    当算法没有创建额外存储空间时,空间复杂度可以简单地理解成为O(1)。

    数组

    是随机存取的,因此,访问结点的时间复杂度为 O(1),增加结点、删除结点的时候需要移动新增结点或待删除结点后面的元素,因此,时间复杂度为 O(n)。

    线性表

    逻辑上连续但物理上分开存放的。
    线性表也叫顺序表,在线性表中的数据元素,其关系是一一对应的,即除了第一个数据元素
    和最后一个数据元素之外,其他数据元素都是首尾相接的。
    本题中,对于选项 A,线性表是随机存取结构,当对其执行插入和删除操作时,只要不是针
    对最后一个元素,此时都需要进行元素的搬家,最坏情况下的时间复杂度是 O(n)。

    线性结构的基本特征为:
    1)集合中必然存在唯一的一个“第一元素” 。
    2)集合中必然存在唯一的一个“最后元素” 。
    3)除最后一个元素外,均有唯一的后继。
    4)除第一个元素外,均有唯一的前驱。

    查询、修改操作数组更快,但插入、删除等操作线性表更快。

    存储结构有:散列、顺序、链式、索引。
    线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表的数据元素。
    链式存储结构又叫链接存储结构, 在计算机中用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的) 。它不要求逻辑上相邻的元素在物理位置上也相邻。因此,它没有顺序存储结构所具有的弱点,但也同时失去了顺序表可随机存取的优点。
    链式存储结构有以下 5 个特点:
    1)比顺序存储结构的存储密度小(每个结点都由数据域和指针域组成,所以,相同空间内假设全存满,则链式存储比顺序存储所能存储的数据少) 。
    2)逻辑上相邻的结点物理上不必相邻。
    3)插入、删除灵活(不必移动结点,只要改变结点中的指针) 。
    4)查找结点时链式存储要比顺序存储慢。
    5)每个结点由数据域和指针域组成。
    链式结构的插入和删除操作只需要修改插入和删除结点以及其前驱结点的指针域即可, 而顺序存储结构在插入和删除操作的时候需要执行大量数据的移动操作。 由此可以看出, 顺序表适合随机访问,不适合插入和删除操作,而链式表适合插入和删除操作,不适合随机访问操作。散列表适合查找运算,索引表在插入和删除的时候还需要修改索引表,由此链式表最适合插入和删除操作。

    LIFO,只有一个口子
    先看这个

    队列

    FIFO,有入口、出口
    队列的插入只能从队列的一端操作,我们称这端为队尾;对应的,移除只能从另一端出来,我们称之为队首
    队列的实现有两种方式:数组实现和链表实现
    用数组实现的队列有两种:一种是顺序队列,另一种是循环队列
    队列先入先出的特点,使得其应用非常广泛,比如队列作为“缓冲区”,可以解决计算机和外设速度不匹配的问题,FIFO的特点保证了数据传输的顺序;除此之外队列在后面树的层序遍历中也有应用,FIFO的特点保证了处理顺序不会出错。
    先看这个

    链表

    基本概念
    链表特点
    如何判断链表有环?
    https://itimetraveler.github.io/2017/12/24/【算法】如何判断链表有环/

    树与二叉树


    二叉树
    二叉树是每个节点最多有两个子树的树结构。
    二叉树是非线性数据结构,即每个数据结点至多只有一个前驱,但可以有多个后继,可以使用顺序存储(在数组中的下标表示一个结点与其孩子和父结点的关系)和链式存储(用链表来表示一棵二叉树)两种结构来存储。
    对任何一棵二叉树 T,如果其终端结点数为 n0,度为 2 的结点数为 n2,则n0 = n2 + 1。
    二叉树中当前k节点的左子节点索引:2k+1;
    当前k节点的右子节点索引:2k+2
    当前节点k的父节点:(k-1)/2

    完全二叉树

    是指除最后一层外,每一层上的结点数均达到最大值。
    完全二叉树需要符合以下两点:
    1)所有叶子节点都出现在k层或k-1层,并且从1~k-1层必须达到最大节点数。
    2)第k层可以是不满的,但是第k层的所有节点必须集中在最左边。
    最后一个叶子的父节点:length/2-1;或(lastIndex - 1) / 2

    满二叉树

    是指树中除最后一层无任何子结点外, 每一层上的所有结点都有两个子结点的二叉树。
    满二叉树中结点的个数为 1、2、4、8。
    一棵深度为 k,且有 (2^k - 1) 个节点称之为满二叉树。

    排序二叉树/二叉查找树BST

    来自二分查找的思想。
    优点:查找/插入一个数所需的最大搜索次数,等于该二叉树的高度。
    缺点:多次插入新节点可能导致树的不平衡(为了解决该问题,产生了红黑树),如图:
    可能导致线性化
    1)若左子树不为空,则左子树上所有结点的值均小于它的根结点的值。
    2)若右子树不为空,则右子树上所有结点的值均大于或等于它的根结点的值。
    3)左、右子树也分别为排序二叉树。
    4)没有键值相等的结点。

    红黑树

    是一种自平衡的二叉查找树。
    java中TreeMap、TreeSet底层
    1.每个节点非红即黑.
    2.根节点是黑的。
    3.每个叶节点都是黑的.
    4.如果一个节点是红的,那么它的两儿子都是黑的(从每个叶子到根的所有路径上不能有两个连续的红色节点,可以有两个连续黑节点)。
    5.对于任意节点而言,其到叶子点的每条路径都包含相同数目的黑节点。

    这些限制使得红黑树是自平衡的,体现在:
    从根节点到叶节点的最长路径不会超过最短路径的2倍。

    但是当删除或插入节点时,需要做一些调整来维持这些规则,一般是联合着完成而不是只用一个:
    1.变色
    要黑黑不要红红
    2.旋转
    左旋转:逆时针旋转红黑树的两个节点,使得父节点被自己的右孩子取代
    左旋转
    右旋转:顺时针旋转红黑树的两个节点,使得父节点被自己的左孩子取代
    右旋转

    平衡二叉树 (Balanced Binary Tree)/AVL 树

    它是一棵空树或它的左右两个子树的高度差的绝对值不超过 1,并且左右两棵子树都是一棵平衡二叉树。
    完全二叉树一定满足平衡二叉树的性质。

    B/B+树

    科普
    注意B-树就是B树,-只是一个符号。
    B/B+树是为了磁盘或其它存储设备而设计的一种平衡多路查找树(相对于二叉,B树每个内节点有多个分支),与红黑树相比,在相同的的节点的情况下,一颗B/B+树的高度远远小于红黑树的高度。
    B/B+树上操作的时间通常由存取磁盘的时间和CPU计算时间这两部分构成,而CPU的速度非常快,所以B树的操作效率取决于访问磁盘的次数,关键字总数相同的情况下B树的高度越小,磁盘I/O所花的时间越少。

    其他树

    B树,B+和红黑树
    B树,B+树,红黑树应用场景笔记

    堆(二叉堆)可以视为一棵完全的二叉树,完全二叉树除了最底层之外,每一层都是满的,这使得堆可以利用数组来表示(普通的一般的二叉树通常用链表作为基本容器表示),每一个结点对应数组中的一个元素。
    有大顶堆和小顶堆两种。大顶堆(小顶堆)的特点是根结点的值最大(最小) ,且根结点的子树也为一个大顶堆(小顶堆)。即子节点的键值或索引总是小于(或者大于)它的父节点。
    堆与堆排序

    hash算法

    用来提高从集合中查找元素的效率,它将集合分成若干存储区域。每个对象计算出一个哈希码,将哈希码分组,每组对应某个存储区域,根据一个对象的哈希码就可以确定该对象存储的区域了。

    应用:哈希表就是一种以 键-值(key-indexed) 存储数据的结构,我们只要输入待查找的值即key,即可查找到其对应的值。
    如果没有内存限制,那么可以直接将键作为数组的索引。那么所有的查找时间复杂度为O(1);如果没有时间限制,那么我们可以使用无序数组并进行顺序查找,这样只需要很少的内存。哈希表使用了适度的时间和空间来在这两个极端之间找到了平衡。只需要调整哈希函数算法即可在时间和空间上做出取舍。
    应用:当集合添加新元素时,先调用该方法定位到该对象应该放置的物理位置,若该位置已有元素,会调用equals方法比较它们是否相同,相同就不用再存一遍了;不同就散列其他的地址。

    Hash算法总结
    https://blog.csdn.net/v_JULY_v/article/details/6256463

    https://www.cnblogs.com/snail-lb/p/5449557.html

    常见的数据结构的操作性能:

    1) 有序数组: 查找的时候可以采用二分查找法, 因此, 查找的时间复杂度为 O(logn), 其中,n表示数组序列的长度。由于数组中的元素在内存中是顺序存放的,因此,删除数组中的一个元素后,数组中后面的元素就需要向前移动。在最坏的情况下,如果删除数组中的第一个元素,那么数组中后面的 n-1 个元素都需要向前移动,移动操作的次数为 n-1,因此,此时的时间复杂度为 O(n)。插入操作与删除操作类似,都需要数组中元素的移动,因此,其时间复杂度也为 O(n)。

    2)有序链表:链表(以单链表为例)的存储特点为:每个结点的地址存储在它的前驱结点的指针域中,对链表的遍历只能从链表的首结点开始遍历,因此,此时查找的时间复杂度为O(n),其中,n 表示链表的长度。对于删除和插入操作,虽然删除和插入操作的时间复杂度都为 O(1)(因为不需要结点的移动操作) ,但是在删除前首先需要找到待删除结点的地址,这个操作的时间复杂度为 O(n), 在插入结点前首先也要找到结点应该被插入的地方, 这个操作的时间复杂度也为 O(n),因此,插入与删除的时间复杂度都为 O(n)。

    3)AVL 树(平衡二叉树) :AVL 树是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。由于树的高度为 logn,其中,n 表示树中结点的个数, 因此, 查找的时间复杂度为 O(logn), 显然, 删除与插入的时间复杂度也为 O(logn)。

    4)Hash 表:Hash 表通过 Hash 值就可以定位到元素的位置,因此,查找、插入与删除的时间复杂度都为 O(1)。

    5)普通数组:查找的时候只能顺序地遍历数组,在最坏的情况下需要对数组中所有的元素遍历一遍,因此,此时的时间复杂度为 O(n),其中,n 表示数组序列的长度。插入的时候只需要把元素插入到数组的最后一个元素的后面即可,因此,时间复杂度为 O(1),删除操作也需要移动这个元素后面的所有的元素,因此,此时的时间复杂度也为 O(n)。

    6)普通二叉树:在最坏的情况下,有 n 个结点的树的高度为 n,因此,查找、插入与删除的时间复杂度都为 O(n)。

    从上面的分析可以发现,平衡二叉树的查找和删除的时间复杂度都是 O(logn),Hash 表的查找、 插入的时间复杂度都是 O(1)。 因此, 这两个数据结构有较好的查找和删除的性能。

  • 相关阅读:
    近似计算π(for循环)
    apache部署mo_python
    文件注释方法
    算法效率的度量
    ssh
    使用类名创建对象
    筛选网址
    常用django命令
    查看和关闭端口
    update脚本出错
  • 原文地址:https://www.cnblogs.com/cashew/p/10724459.html
Copyright © 2011-2022 走看看