数据结构-线性表

数据结构-线性表

线性表结构:线性表:数组、链表、栈、队列前端

1.数组:连续的内存空间。java


  1.1  查找:随机查找的时间复杂度为O(1),注意,只是随机查找(用下标的方式)。排序后的二分查找时间复杂度O(logn)数据库

    中间插入和删除:须要搬移元素位置,时间复杂度为O(n)编程

    开头和结尾插入和删除:O(1)后端

    插入优化技巧:若是条件容许,插入到第K个位置时,能够把第K个位置的元素移动到最后,减小数据搬运数组

    删除优化技巧:若是条件容许,能够几个删除一块儿后,再搬移元素。(相似JVM的垃圾回收,标记清除法)

  1.2 JAVA中的ArrayList封装了数组,相比数组优点:动态扩容浏览器

      (1)扩容时,新建一个大的数组,而后数据拷贝到这个新的数组。缓存

    (2)扩容大小:原来容量的1.5倍数据结构

    (3)数组和ArrayList的选择:通常使用ArrayList,可是对于底层框架的开发,须要把性能作到极致,能够选择数组。并发

  1.3 二维数组能够表示矩阵

    针对稀疏矩阵的表示:若是直接表示会浪费存储空间。能够采用三项式来表示。

    A(0,1)表示矩阵的行数

    A(0,2)表示矩阵的列数

    A(0,3)表示矩阵的非零项的总数

    A(i,j,value) 表示非零的项。i从1开始,第i行第j列的值为value

  1.4 数组和多项式

    P(x) = a0 + a1x + a2*x^2 + a3*x^3 + ... + + an*x^n

    好比 2x^5 + 3x^4 + 5x^2 + 4x + 1

    方法一:使用n+2长度的一维数组存储,第一个元素是最大的指数n,其他元素按n递减存储多项式的系数。若是没有的存储0

      A = {5,2,3,0,5,4,1} ,其中这里没有x^3的系数,因此第四项为0

      缺点:若是有x^100,那么素组的长度为100+1

    方法二:只存储多项式非零项。第一个元素为多项式非零项的个数。

      A = {5,2,5,3,4,5,2,4,1,1,0}

      缺点:计算时可能会更复杂些

2.链表:不要求内存空间连续

  2.1  插入和删除:适合大量的操做 O(1);查询: O(n)

 

  2.2  JAVA中的LinkedList为双向链表,有next也有previous

    LinkedList能够实现栈、队列以及双端队列等数据结构

    LinkedList能够实现LRU缓存机制

  2.3  单向链表:指针和数据(第一个接节点是链表头指针,最后一个指针设置为null)

    循环链表:最后一个指针指向链表头部,从任何一个节点入手,能够遍历全部其余节点

    环形链表:一般应用于内存工做区与输入/到处缓冲区

    双向链表:优点是能够轻松找到先后节点

    双向循环链表

 

  2.4 链表和多项式:和数组的方法同样,只是链表实现的好处是适合多项式内容变更

 

  2.5 环形链表能够实现稀疏矩阵:优势是矩阵变动时不须要大量移动数据

 

3.跳表(跳跃表):经过多级索引使得链表可以实现二分查找,加速链表的随机查询效率,似于二分查找。

    查询(不支持随机查询):O(logn)

    空间复杂度:O(n)

    场景: Redis使用了跳表。

    HBase MemStore的也使用的跳表。为何呢?

      HBase 属于 LSM Tree 结构的数据库,LSM Tree 结构的数据库有个特色,实时写入的数据先写入到内存

      内存达到阈值往磁盘 flush 的时候,会生成相似于 StoreFile 的有序文件,而跳表刚好就是自然有序的

      因此在 flush 的时候效率很高,并且跳表查找、插入、删除性能都很高,这应该是 HBase MemStore 内部存储数据使用跳表的缘由之一。

      HBase 使用的是 java.util.concurrent 下的 ConcurrentSkipListMap()。

 

4.栈:先入后出,当作桶。(操做受限的数组或链表结构)

  4.1 添加、删除复杂度都是O(1);查询: O(n)

  4.2 能够数组实现(顺序栈)和链表实现(链式栈)(数组不利于大小动态变化,可是优势是编程简单)只须要一个top指针指向栈顶元素。

  4.3 应用:浏览器前进后退

        函数调用

            表达式取值

 

5.队列Queue:先入先出,通俗理解:排队。(操做受限的数组或链表结构)

 

  5.1 添加、删除复杂度都是O(1);查询: O(n)

    在高级语言中,通常不用纯粹的栈和队列,java能够用双端队列替代。

  5.2 能够数组(顺序队列)和链表(链式队列)实现。

      线程池中的各类策略:

    链表实现:无界队列,不合适响应时间敏感的。

    数组实现:有界队列,适合响应时间敏感的。

 

    环形队列与链式队列的选择:若是能够肯定最大的大小,那么选择环形队列。若是不能肯定,那么选择链式队列。

 

  5.3 须要两个指针front和rear分别指向前端和后端。

 

  5.4 应用:做业调度、磁盘的缓冲区。

 

  5.5 双端队列Deque:两边均可以进出。两边都须要front和rear指针。

  5.6 循环队列 : MapReduce中Shuffle时使用了。

            注意:环形队列是使用数组实现的,解决顺序队列的数据搬运问题。

  5.7 优先队列Priority Queue

    插入和删除:O(1)

    取出操做:O(logn),按照优先级

    底层实现能够多样:heap、bst、treap

 

    java中实现:PriorityQueue

  5.8 阻塞队列和并发队列(CAS)

 

6.哈希表Hash table(散列表):经过哈希函数(散列函数)映射值。

  6.1 模型:Hash函数获得数组下标 -> 数组(链表做为数组的元素)

    插入和删除:O(1)

    查询:O(1)

    说明:可能后面链表查询的复杂度不为1,可是通常hashCode一致的比较少,

          因此链表的元素个数其实颇有限,能够认为就是O(1)。

  6.2 哈希函数

    (1)除后取余数法

    (2)平方取中

  6.3 java 7中的HashMap是数组和链表的结合体。JAVA 8中是数组 + 红黑树实现。

    (1)对象的HashCode是用来在散列存储结构中肯定对象的存储地址的。

    (2)若是两个对象的HashCode相同,即在数组中的地址相同。而数组的元素是链表。这两个对象会放在同一链表上。

    (3)如何肯定是同一个对象? 经过equals方法。

    (4)HashMap默认的加载因子是0.75,默认最大容量是16。

       所以能够得出HashMap的默认实际容量是:0.75*16=12,到了12就会扩容。

                     扩容大小:扩容原来的一倍。

                还有经常使用的 HashMap HashSet。

 

7. 应用:算术表达式的表示方法

  中序法(操做数1-运算符-操做数2): 2*3 + 4*5

  中序表达法符合人的习惯,不过计算机处理不方便

  前序法(运算符-操做数1-操做数2): +*23*45

  经常使用的计算机处理方式

    后序法(操做数1-操做数2-运算符): 23*45*+

  经常使用的计算机处理方式(比前序经常使用)

  7.1 利用堆栈实现表达式运算:最简单的是后续表达式求值-只须要一个栈。

 

  7.2 可使用二叉树的方法

 

  7.3 中序转前序/后序

    2*3 + 4*5

  (1)括号法: 先括号括起来((2*3) + (4*5))

    中序转前序

      用括号内的运算符替代左括号,近者优先:+*23)*45))

      去掉全部右括号:+*23*45

    中序转后序

      用括号内的运算符替代右括号,近者优先:((23* (45*+

      去掉全部左括号:23*45*+

  (2)堆栈法

  7.4 前序或后序转中序

  (1)括号法

  (2)堆栈法

相关文章
相关标签/搜索