序言
线性表
顺序存储(数组:查询速度快)
链式存储(链表:增加删除速度快)
链表主要解决动态存储数据的问题.
链表增加新节点和删除节点方便,链表比普通查找(顺序引导查找)方便。
静态链表内存大小是规定了的,动态链表可以根据类型来申请不同的内存大小。
线性表的两种存储结构
1.顺序表(数组)
即线性表用顺序存储结构保存数据,数据是连续的。
顺序表的优点:随机访问的速度很快;空间利用率高(存储空间连续分配,不存在浪费)。
顺序表的缺点:顺序表的长度是固定的,如果超出分配的长度就会造成溢出,如果存放的数据太少就会造成空间浪费。
在插入元素和删除元素时(尤其插入和删除的位置不在尾部时),会移动大量的元素,造成性能和效率低下。
2.链表
即线性表用链式存储结构保存数据,数据是不连续的。
线性表是什么
1.线性表是最基本、最简单的一种数据结构。
2.线性表中元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的。
3.线性表具有以下几个特征:
①有且只有一个“首”元素
②有且只有一个“尾”元素
③除“首”元素之外,其余元素都有唯一的前驱元素。
④除“尾”元素之外,其余元素都有唯一的后继元素。
链表是什么
从内存角度出发: 链表可分为静态链表、动态链表。
从链表存储方式的角度出发:链表可分为单链表、双链表、以及循环链表。
1.静态链表
2.单链表
3.单向循环链表
4.双链表
5.双向循环链表
单链表是不错的,但是呢,人无完人,玉有微瑕,单链表也不是完美的,单链表的缺点是只能往前,不能后退,虽然有循环单链表,但后退的成本还是很高的,需要跑一圈。
在这个时候呢,双向链表就应运而生了,再加上循环即双向循环链表就更加不错了。
所谓双向链表只不过是添加了一个指向前驱结点的指针,双向循环链表是将最后一个结点的后继指针指向头结点。
顺序表和单链表的比较
顺序表:
优点:主要优点是读取元素的速度较快,以及内存空间利用效率高;
缺点:主要缺点是需要预先给出顺序表的最大元素个数,而这通常很难准确做到。当实际的元素个数超过了预先给出的个数,会发生异常。另外,顺序表插入和删除操作时需要移动较多的数据元素。
单链表:
优点:主要优点是不需要预先给出最大元素个数。另外,单链表插入和删除操作时不需要移动数据元素;
缺点:主要缺点是每个节点都需要分为地址域和数据域,因此单链表的空间利用率略低于顺序表。另外,单链表读取一个元素的时间复杂度为O(n);而顺序表读取一个元素的时间复杂度为O(1)
数组、链表、Hash
1.数组:
数组是将元素在内存中连续存放,由于每个元素占用内存相同,可以通过下标迅速访问数组中任何元素。但是如果要
在数组中增加一个元素,需要移动大量元素,在内存中空出一个元素的空间,然后将要增加的元素放在其中。同样的
道理,如果想删除一个元素,同样需要移动大量元素去填掉被移动的元素。如果应用需要快速访问数据,很少插入和
删除元素,就应该用数组。
2.链表:
链表中的元素在内存中不是顺序存储的,而是通过存在元素中的指针联系到一起,每个结点包括两个部分:一个是存
储数据元素 的数据域,另一个是存储下一个结点地址的 指针。如果要访问链表中一个元素,需要从第一个元素始,
一直找到需要的元素位置。但是增加和删除一个元素对于链表数据结构就非常简单了,只要修改元素中的指针就可以
了。如果应用需要经常插入和删除元素你就需要用链表。
3.Hash:
hash表其实是结合了数组和链表的优点,进行的折中方案。平衡了数组和链表的优缺点。hash的具体实现有很多种,但是需要解决冲突的问题。
不相同的数据通过hash函数得到相同的key值。这时候,就产生了hash冲突。解决hash冲突的方式有两种。一种是挂链式,也叫拉链法。
挂链式的思想在产生冲突的hash地址指向一个链表,将具有相同的key值的数据存放到链表中。另一种是建立一个公共溢出区。
将所有产生冲突的数据都存放到公共溢出区,也可以使问题解决。
.Net数据结构
Array是始终是连续存放的,而ArrayList的存放不一定连续。
线性表那就是List
.NET 框架中一些集合实现了IList接口,如ArrayList,ListDictionary,StringCollection,String Dictionary.
.NET 线性表中顺序存储采用的是数组,而链式的存储方式则是:IList接口。
栈和队列是非常重要的两种数据结构,栈和队列也是线性结构,线性表、栈和队列这三种数据结构的数据元素和元素的逻辑关系也相同
差别在于:线性表的操作不受限制,栈和队列操作受限制(遵循一定的原则),因此栈和队列也称为受限制的线性表。
和数组一样是一种数据结构,数组不支持高效的删除和插入,因为要涉及到数据的移动,并且数组的大小是固定的。
但是链表克服了这些缺点,但是他也有自己的缺点,需要额外的内存存储维持链表的变量,并且不能像数组那样随机访问。
所以这就是计算机科学中的tradeoff吧,有得必有失。
.NET中自带的链表是LinkedList类,并且已经直接实现成了双向循环链表。
Java数据结构
List 只要有两个实现类(ArrayList 和linkedList ),ArryList是基于数组实现,LinkedList是基于链表实现。
LinkedList是List接口的双向链表实现。由于是链表结构,所以长度没有限制;而且添加/删除元素的时候,只需要改变指针的指向(把链表断开,插入/删除元素,再把链表连起来)即可,非常方便,而ArrayList却需要重整数组 (add/remove中间元素)。所以LinkedList适合用于添加/删除操作频繁的情况。
LinkedList是java对双链表的一种实现,定义了链表的双端操作。这种链表的集合有一个很好的优点:其可以实现元素的快速添加和删除。但也有一个很大的缺点:如果获取一个指定位置的元素,则要通过遍历的方式,这种方式十分低效率。所以在集合选取的时候也考虑此集合主要用于元素的查看和修改还是元素的增删。
资料
http://www.cnblogs.com/songwenjie/p/8678212.html
https://www.cnblogs.com/fivestudy/p/10674966.html
https://blog.csdn.net/javazejian/article/details/52953190
动画模拟:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html