学习编程的第一步,先打印一个“hello world”,表示已经和计算机开始正常对话了。
接下来一般的教程就是按部就班的讲 这门语言的数据类型。除了 int, string等基础类型,对于操作多个数据,编程语言还提供了数组,字典。
作为数据结构的基础,线性表有2种类型,一个是数组,另外一个是链表。然而很多编程语言的内置了数组,像Python、Golang、javascript,但是原生内置基本链表这个数据类型的恐怕只有Java了。
为什么会这样呢?
首先比较下两者的区别:
数组是一块连续的空间,找出数组中任何位置元素的值,根据首地址 和每个元素占用的空间,一计算,就能好找到 目标元素的地址,从而找到这个地址保存的值,复杂度为O(1)。但是对于删除 和插入为了保证其连续性就需要将数组的元素全部都移动一次。
链表因为在内存中存储的位置并不连续,所以插入 和删除操作时 只需要操作目标位置 前后结点的指针指向即可,复杂度为O(1), 但是当需要进行查找操作,只能从到到尾开始遍历,所以复杂度就是O(n)。
回答标题的问题:
1、随机访问效率相比链表更高,只需通过下标计算即可找到目标元素的地址,而链表则需依次遍历。
2、因为数组在内存中是连续的,每次cpu缓存 也会把相邻的数据块加入缓存。极大提升程序的效率;
3、因为链表中的每个结点都需要消耗额外的存储空间去存储一份指向下一个结点的指针,所以内存消耗会翻倍;
4、如果进行频繁的插入、删除操作,数组是申请一块空间进行操作。而链表则频繁的内存申请和释放,容易造成内存碎片,如果是 Golang 语言,就有可能会导致频繁的 GC(Garbage Collection,垃圾回收)。
那么链表这一结构,究竟有哪些应用场景呢?
1、文件系统:
通常当你格式化硬盘时会让你选择fat32、ntfs格式,其实就是让你选择存储链表空间规模及格式。为提高系统效率,你有时需要做文件碎片整理,这说明一个文件的数据不一定是连续存放的,那么操作系统是如何知道把不连续的数据合成一个文件提供给你的呢?其实就是通过访问一个指向文件数据区的链表得到的。
2、LRU缓存
可以通过HashMap+双向链表实现。HashMap保证通过key访问数据的时间为O(1),双向链表则按照访问时间的顺序依次穿过每个数据。
3、git
git里面每次commit都是创建一个node,node包含了删减后的新文件,然后node指向前一个commit的node。git checkout、delete branch、merge、rebase这些基本上都是以链表操作为主。git应该算是对linked list很好的应用。不用linked list应该很难高效地实现git提供的功能。
链表的应用场景挺多的,实际上 内存池、操作系统的进程管理、网络通信协议栈的trunk管理等都用到了链表的思想。
这2种数据结构,从设计之初,在内存中的布局不同,一个为集中的内存块,一个相对松散,需要靠记录地址串行。
到现如今的 一个为日常编程操作的结构,另一个则在计算机中的文件系统,操作系统管理广泛使用,这也许从被设计之初的差距 便已决定其日后的走向,和应用场景。