时间复杂度

丶灬走出姿态 提交于 2019-12-01 16:23:39
栈 什么是栈? 栈就类似放盘子,盘子一块一块叠起来,如果我们拿盘子的话只能拿到刚刚放下去的盘子。 总结来说就是,先进者后出,后进者先出,的一种数据结构 栈对比数组和链表 我们从栈的特点上,我们知道它的操作对比数组和链表,受到了很强的限制,增加和修改都只有单一的方式,没有数组和链表那样的灵活性。 栈的两种实现方式 顺序栈: 用数组实现的 链式栈: 用链表实现的 可动态扩容的顺序栈-复杂度分析 当插入数据,顺序栈没有空间的时候,就会重新请求一块2背的内存,然后进行原来的数据的搬运,然后在插入数据。 当顺序栈的内存够用 出栈的时间复杂度都为O(1) 但是入栈的话要考虑到内存满的时候,这个时候就满足了均摊的时间复杂度了,内存还有的话,时间复杂度一直为O(1),只有当内存满了的时候时间复杂度为O(n),但是均摊下来,时间复杂度就是O(1) 一般均摊时间复杂度=最好情况时间复杂度 栈的实际应用 栈在函数调用的应用-函数调用栈 我们知道真正执行代码的是我们的线程,每个线程都有一块独立的内存空间,这个内存就是栈这种结构,用来存储函数调用的时候的临时变量。每进入一个函数,就会将临时变量作为一个栈帧入栈,当被调用函数函数执行完成,返回之后,将这个函数的对应的栈帧出栈 int main(){ int a = 1; int ret = 0; int res = 0; ret = add(3,5); res

排序算法

隐身守侯 提交于 2019-12-01 15:34:31
说道排序,我们经常提到时间复杂度和空间复杂度,那么什么是时间复杂度什么又是空间复杂度呢? 时间复杂度:时间复杂度是指执行这个算法所需要的计算工作量 求解算法的时间复杂度的具体步骤是:   ⑴ 找出算法中的基本语句;   算法中执行次数最多的那条语句就是基本语句,通常是最内层循环的循环体。   ⑵ 计算基本语句的执行次数的数量级;   只需计算基本语句执行次数的数量级,这就意味着只要保证基本语句执行次数的函数中的最高次幂正确即可,可以忽略所有低次幂和最高次幂的系数。这样能够简化算法分析,并且使注意力集中在最重要的一点上:增长率。   ⑶ 用大Ο记号表示算法的时间性能。   将基本语句执行次数的数量级放入大Ο记号中。   如果算法中包含嵌套的循环,则基本语句通常是最内层的循环体,如果算法中包含并列的循环,则将并列循环的时间复杂度相加 空间复杂度:空间复杂度是指执行这个算法所需要的内存空间   空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度;计算机上占用内存包括   程序代码所占用的空间,输入输出数据所占用的空间,辅助变量所占用的空间这三个方面。   程序代码所占用的空间取决于算法本身的长短,输入输出数据所占用的空间取决于要解决的问题,   是通过参数表调用函数传递而来,只有辅助变量是算法运行过程中临时占用的存储空间,与空间复杂度相关;   通常来说

算法

坚强是说给别人听的谎言 提交于 2019-12-01 13:42:37
什么是算法 算法 (Algorithm): 一个计算过程, 解决问题的方法 Niklaus Wirth: "程序=数据结构+算法" 时间复杂度 详情 ⽤用来评估算法运⾏时间或者运行效率的一个式⼦ 一般来说, 时间复杂度高的算法比时间复杂度低的算法慢 常见的时间复杂度排序(按效率排序) O(1)<O(logn)<O(n)<O(nlogn)<o(n^2)<O(n^2logn)<O(n^3) 第一类 对于一个循环,假设循环体的时间复杂度为 O(n),循环次数为 m,则这个 循环的时间复杂度为 O(n×m) O(1) print('Hello World') print('Hello World') print('Hello lxx') print('Hello lyy') O(n) for i in range(n): print('Hello World') 第二类 对于多个循环,假设循环体的时间复杂度为 O(n),各个循环的循环次数分别是a, b, c...,则这个循环的时间复杂度为 O(n×a×b×c...)。分析的时候应该由里向外分析这些循环。 O(n**2) for i in range(n): for j in range(n): print('Hello World') for i in range(n): print('Hello World') for j in

2、线性表之顺序表

半城伤御伤魂 提交于 2019-12-01 13:41:57
一、顺序表 线性表是某类元素的一个集合,还记录着元素之间的一种顺序关系。 顺序表:将元素顺序地存放在一块连续的存储区里,元素间的顺序关系由它们的存储顺序自然表示。 二、顺序表的基本形式 顺序表的数据元素本身连续存储,每个元素所占的存储单元大小固定相同,元素的下标是其逻辑地址,而元素存储的物理地址(实际内存地址)可以通过存储区的起始地址Loc (e0)加上逻辑地址(第i个元素)与存储单元大小(c)的乘积计算而得,即: 访问指定元素时无需从头遍历,通过计算便可获得对应地址,其时间复杂度为O(1)。 三、顺序表的结构 一个顺序表的完整信息包括两部分,一部分是表中的元素集合,另一部分是为实现正确操作而需记录的信息,即有关表的整体情况的信息,这部分信息主要包括元素存储区的 容量 和当前表中已有的 元素个数 两项。 四、顺序表的两种基本实现方式 一体式结构,存储表信息的单元与元素存储区以连续的方式安排在一块存储区里,两部分数据的整体形成一个完整的顺序表对象。一体式结构整体性强,易于管理。但是由于数据元素存储区域是表对象的一部分,顺序表创建后,元素存储区就固定了。 分离式结构,表对象里只保存与整个表有关的信息(即容量和元素个数),实际数据元素存放在另一个独立的元素存储区里,通过链接与基本表对象关联。 五、元素存储区替换 一体式结构由于顺序表信息区与数据区连续存储在一起,所以若想更换数据区

链表

女生的网名这么多〃 提交于 2019-12-01 13:35:12
链表 链表的底层实现 数组是连续的内存空间,所以内存是必需连续的,但是,链表它是通过指针将一组零散的内存块串联起来使用的。 指针 可以保存地址值(指针)的变量称为指针变量,因为指针变量中保存的是地址值 假如 硬盘最后就剩下100M的内存了,如果剩下的这100M是一块完整的内存,那么就可以声明一个100M的数组,但是链表的要求就没有那么多。但是相反的链表使用的内存会更多,因为它存储这下一个数据的指针。 单链表 链表通过指针将一组零散的内存块串联到一起。其中的内存块我们称为 结点Node ,结点中不仅存储着数据,还有下一个结点的地址,这个结点地址称为 后继指针next 第一个结点称为 头结点 ,最后一个称为 尾结点 , 尾结点 指向为空地址null 时间复杂度分析 插入数据,删除数据 O(1),只要改变结点的后继指针指向就行了 查询数据 O(n)由于内存地址不是连续的,所以不能使用例如数组的那一套,求址算法,只能从头一个一个的去找 循环链表 循环链表是一种特殊的单链表,就是把尾结点的后继指针指向第一个结点,实现了循环的效果 时间复杂度和单链表一样 双向链表 双向链表就是在单链表的基础上,给每一个结点加了一个 前驱结点 这样每个结点不仅能知道后一个结点在哪,前一个结点的位置也知道了。 优点 双向链表可以在时间复杂度为O(1)的情况下找到前一个结点

#119. 非负权单源最短路

白昼怎懂夜的黑 提交于 2019-12-01 13:24:45
题面 代码 似乎数据想让 \(dijstra\) (不优化也行)和 \(SPFA\) 都能过。 我写了个堆优化的 \(dijstra\) ,注意这句话 if(dis[k.second]<-k.first)continue (懒惰删除)非常重要:堆中可能会 按顺序先后放入 若干个距离 从大到小 的相同编号的点,因为这个点的可能被不断更新。然而用过的点是没有再用的意义的,所以我们就需要加个特判(当前点进来过多个,且当前值不是最小,说明已经用这个点来松弛过其他点)或多加个数组。顺序很重要,必须先删除。 当然这样写的时间复杂度是 \(mlogm\) 的,因为每条边都可能会产生一个不必要的点。要提高时间复杂度的话需要换用能删除的数据结构。 \(O(mlogm)\) 来源: https://www.cnblogs.com/May-2nd/p/11688331.html

【题解】Dvoniz [COCI2010]

无人久伴 提交于 2019-12-01 13:06:51
【题解】Dvoniz [COCI2010] 没有传送门,只有提供了 数据 的 官网 。 【题目描述】 对于一个长度为 \(2*K\) 的序列,如果它的前 \(K\) 个元素之和小于等于 \(S\) 且后 \(K\) 个之和也小于等于 \(S\) ,我们则称之为 \(\text{interesting}\) 。现给定一个长度为 \(N\) 的序列 \(a\) ,要求输出以每个元素开头能找到的最长 \(\text{interesting}\) 序列 的长度。 【输入】 第一行两个整数 \(N,S\) 。 接下来 \(N\) 行,每行一个整数,表示序列中每个元素 \(a[i]\) 。输入保证每个元素为正数且和小于 \(2*10^9\) 。 【输出】 \(N\) 行每行一个整数,第 \(i\) 行表示以 \(a[i]\) 开头的最长的 \(\text{interesting}\) 序列。如果不存在,则输出 \(0\) 。 【样例】 样例输入: 5 10000 1 1 1 1 1 样例输出: 4 4 2 2 0 【数据范围】 \(100 \%:\) \(2 \leqslant n \leqslant 10^5,\) \(1 \leqslant S \leqslant 2*10^9\) 【分析】 一道灰常 \(\text{interesting}\) 的题。 蒟蒻英语差没有细看官方 题解

Java容器总结

三世轮回 提交于 2019-12-01 13:06:49
容器总结 Java容器工具包框架图 List,Set,Map三者的区别 List(对付顺序的好帮手): List接口存储一组不唯一(可以有多个元素引用相同的对象),有序的对象 Set(注重独一无二的性质): 不允许重复的集合。不会有多个元素引用相同的对象。 Map(用Key来搜索的专家): 使用键值对存储。Map会维护与Key有关联的值。两个Key可以引用相同的对象,但Key不能重复,典型的Key是String类型,但也可以是任何对象。 Arraylist 与 LinkedList 区别 是否保证线程安全: ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全; 底层数据结构: Arraylist 底层使用的是 Object 数组;LinkedList 底层使用的是 双向链表 数据结构(JDK1.6之前为循环链表,JDK1.7取消了循环。注意双向链表和双向循环链表的区别,下面有介绍到!) 插入和删除是否受元素位置的影响: ① ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。 比如:执行add(E e) 方法的时候, ArrayList 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是O(1)。但是如果要在指定位置 i 插入和删除元素的话(add(int index, E element) )时间复杂度就为

【数据结构】链表

纵然是瞬间 提交于 2019-12-01 12:30:05
链表和数组: 链表是一个相对简单的数据结构,与数组不同的是,它并不需要一块连续的内存空间,而是通过指针将一组零散的内存块串联起来使用。 单链表: 我们吧内存块称为链表的结点,为了将所有的结点串起来,每个链表的结点除了存储数据意外,还需要记录链上的下一个结点的地址。这个记录下个结点的指针叫做后继指针next。 我们习惯吧的第一个结点称为头结点,把最后一个结点叫做尾结点。其中,头系欸但用来记录链表的基地址,而尾结点指向一个空地址Null,表示这是链表上的最后一个结点。 单链表的查找、插入,删除操作: 在进行数组的插入、删除操作时,为了保持内存数据的连续性,需要做大量的数据搬移,所以时间复杂度为o(n),而链表插入或者删除数据,由于本身链表的存储空间本身不是连续的,只需要考虑相邻结点的指针改变,其对应的时间复杂度为o(1)。 相对的,链表不能通过下标的随机访问高效访问第K个元素,只能根据指指针一个结点一个结点地依次遍历。其时间复杂度为o(n)。 循环链表和双向链表: 循环链表是一种特殊地单链表,其唯一区别在于循环链表指针指向头结点,适合处理具有环形结的数据,比如约瑟夫问题。 单向链表只有一个方向,结点只有一个后继指针next指向后面的结点,而双向链表多了一个前驱指针prev指向前面的结点。由于双向链表需要额外的空间来存储前驱结点的地址,所以双向链表要比单链表占用更多的内存空间

数组

随声附和 提交于 2019-12-01 10:25:05
数组 数组概念 数组(Array)是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。 线性表 线性表就是数据排成像一条线一样的结构。表就是数据排成像一条线一样的结构。每个线性表上的数据最多只有前和后两个方向。数组、链表、队列、栈等也是线性表结构。 非线性表 二叉树、堆、图等,在非线性表中,数据之间并不是简单的前后关系。 连续的内存空间和相同类型的数据 优点:随机访问(下标查找数据) 缺点:删除、插入数据非常的低效 数据存储原理和为啥下标从0开始 案例 int[] a = new int[10] 右边的1000到1039为连续的内存空间,其中每个数据占用4个字节数据,因为int 取值代码: a[i]_address = base_address + i * data_type_size 其中 data_type_size 表示数组中每个元素的大小 假设我要拿a[1] a[1]=999+4*1=1003 1000-1003 如果第一个元素的索引不从0开始,每一次都要进行一次-1,对于cpu来说,就是多一次减法指令,以0开始可以提高性能。 时间复杂度分析 根据索引取值 由于根据索引取值,n和代码是不影响的,代码执行时间为一个常数,时间复杂度为O(1) 插入数据 依次从0为开始,时间复杂度为1+2+...n/n=O(n) 如果数据不是有序的