前言

     今天的博客写的很晚,为什么呢?因为当我看完线性表时,我忽然很犹豫:有那么多关于指针内存的操作,数据结构,我身为前端真的会用到吗?于是我在网上一番搜,最后还是觉得需要会,就像很多人说的,数据结构和算法是一个程序员的根基,不会它们我们依然可以当一个熟练的搬运工,但是,它们决定了一个程序员的上限,我刚才想着到底要不要花精力学的时候,忽然想起来react实现局部渲染用到的virtual dom本身就是一个树,顿时觉得很打脸。如果要走的更深,还是要会的。

     我喜欢廉价的纸上谈兵,不太喜欢 show you the code。毕竟资历尚浅,我把博客当做一种笔记来使用,并没打算写成什么教程。如果我的几句话能让你对它有概念上的了解,我觉得就够啦,应用的话毕竟要靠实际项目,以后写项目或者看源码的时候遇到会再拿出来分享,所以眼下想要深入了解的话,还是需要再百度百度啦。

 

线性表

定义:

  线性表是最基本、最简单、也是最常用的一种数据结构。

  线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的(注意,这句话只适用大部分线性表,而不是全部。比如,循环链表逻辑层次上也是一种线性表(存储层次上属于链式存储),但是把最后 一个数据元素的尾指针指向了首位结点)。
  想一下数据库,里面的每条记录都可以理解为一个线性表的数据元素,即前一章所讲的一对一的关系。按照其在内存中的存储结构,可以分为顺序存储和链式存储。

顺序存储

  顺序存储,即在内存中开辟一块连续的地址空间,每个数据元素的长度相等,这样第n个的地址 = 起始地址 + ( n - 1 ) * 一个数据元素的长度。如下:

  这就是顺序存储,内存的基本单位是字节,假设你的每个元素占位是6个字节,那么当你想要查找第4个元素的时候,只需要知道 “起始地址 + 3 * 6 ” 这个地址的具体值。可以认为数组是线性表的实例。

      这种存储结构导致其查找非常轻松,但是插入删除就很困难:如果你想在第4个位置插入一个数字,你需要先把第4~length个元素全部后移,然后再插入这个元素。如果数组很长,这得多麻烦?所以有了链式存储。

 

链式存储

       链式结构存储是离散的,分布在内存的各个角落。每个结点都包括自身数据data和指向下一个结点的next,各个结点之间通过next锁定到下一个结点,形成一个线性的链表。

   链式存储分为单链表,静态链表,循环链表和双向链表。单链表是最常见的,剩下的就具体看需求使用了,比如需要能双向搜索的可以用双向链表。

  •  单链表即上述所说的,结点(可以理解为基本的数据元素)为data和next组成的一个结构体。有一个头结点head,data任意,next指向结点a1;然后有N个a,最后an的next为NULL。即头结点+n个带数据的结点。这样的结构插入删除是比较方便的,直接修改  next即可(插入:本来是a->next = b,加入c,变成c->next = a->next;a->next = c;删除:a->next=b,b->next=c;变成a->next = c,然后删除b结点),可是查找就很麻烦了,需要从头开始遍历next。
  •  静态链表即一个数组,但是每个数据元素包含了data和next,这样查找可以依靠位置,插入可以依靠next。
  •  循环链表即在单链表的基础上删除头结点,最后一个结点的NULL改为a1结点的地址,这样就能实现循环,即最后一个结点后是第一个结点。
  •  双向链表即在单链表的基础上每个结点再加一个指向上一个结点的prior,这样就可以向前查+向后查。