Nicklaus Wirth, 因为一个著名的公式而获得了图灵奖, 那就是"算法+数据结构=程序"。由此可见数据结构的重要性。本系列旨在探索数据结构的实现与原理,使得人人都懂数据结构,都会设计数据结构。
本篇文章为数据结构系列的开篇, 目的很明确,让大家了解数据结构的概念与组成, 帮大家创建一个系统的数据结构知识体系。让我们从0开始,窥见数据结构。
1.什么是数据结构?
先引入百度百科的定义
数据结构是计算机存储、组织数据的方式。
数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。
通常情况下,精心选择的数据结构可以带来更高的运行或者存储[效率]。数据结构往往同高效的检索[算法]和[索引]技术有关。
从以上定义来看,数据结构是数据的一种组织形式。我从这个定义提取了两个重要的因素:
数据元素
特定关系
通俗定义,根据个人理解就是,数据结构是若干数据,根据一定的关系组合在一起形成的组织形式。很抽象?我也这么觉得。下面从两个重要的因素谈起:
生活中任何一个事物都可以看作一个数据元素, 而且每个事物都可以随意赋予一个代表数值;当然平时我们以它实际代表的意义作为它的值。如一双鞋, 一个风扇, 一堆沙子,一个世界;我们分别可以把把它的值看作一双(1),也可以看作两只(2);一台(1),四个扇叶(4);一堆(1), 30万颗(300000);一个(1), 无穷大(正无穷)。从这个例子来看, 万物皆数字(数据元素),它的值你可以随意想象(角度不同,值自然不同)。
生活中所有的事物都是有关系的,这个关系也可以称之为数据元素的特定关系。还是上面的例子, 一双鞋与单独的两只,一台风扇与四个扇叶, 一堆沙子与沙子颗粒, 一个世界与世界内的一切。 两只鞋得左脚与右脚, 风扇与沙子, 鞋,风扇,沙子与世界。万物皆存在关联(没有任何关系的两个事物之间,也称为一种关系)。
从以上说法来看, 我们的世界可以看成一个巨大的数据结构;世界内的任何元素也可以看成一个数据结构。还是那句话,角度不同。
可能很多人纳闷了,说这些干嘛呢,驴唇不对马嘴的? 答案是,我在培养你一种数据结构的眼光。就像是Java中的所有实现你都要看成对象(面向对象), C中的所有实现你都要看成过程(面向过程),不同模块下的同一抽象看成切面(面向切面),数据结构同样如此。只有具备了这种思维,理解起来容易的多,而且你可以根据现实去总结出自己的数据结构;这也是为什么Nicklaus Wirth把所有程序看成是算法+数据结构的组合了。
2.数据结构的关系有什么?
不同的角度下, 数据元素的关系是千千万的;但是总结起来,大抵分为4类:
上图是数据结构的四种关系:集合, 线性关系, 树, 图。 其实是正好囊括生活中的所有关系的,不是么? 解释起来,分别是
集合: 任意两个元素之间都是独立的,也即没有关系
线性: 元素之间存在1对1的关系(两个元素之间只有唯一的对应关系,如1和2, 2和3等)
树: 元素之间存在1对多的关系(每个父节点对应N个子节点, 如A节点对应B和C两个子节点)
图: 元素之间存在多对多的关系(任何一个顶点都可能对应多个关系,如A对应和另外的节点都存在关系)
其实现实生活中的对应关系也是这样, 从无关系(集合),到有关系(线性),再复杂一点(树)从1-1到了1-N,然后再复杂一点(图)从1-N到了N-N, 这就是最复杂的关系了。当然, 说这些只是为了相对好理解。
3.程序(Java)中的数据结构的关系是什么?
Java是一种面向对象编程, 因此在设计数据结构时,会采用各种接口, 抽象类, 继承等;所以Java中的数据结构是一个复杂的关系网络,借用网上一张关系图来看一下
从上图来看, 数据结构的关系还是很复杂的。大抵分为三层: 1) 公共接口层 2) 数据抽象层 3) 数据结构层
公共接口层
主要包括Iterator, Collection, Map; 分别对应迭代器, 集合, 图。 公共接口层主要作用是定义一系列的公共操作,提供一个执行规范。
Iterator
迭代器,我们可以简单的理解为遍历。 它是一个标准的遍历所有对象的接口。
——————————————————————————————
boolean hasNext();
E next();
——————————————————————————————
Collection
集合,我们并不陌生。看上图就知道,它衍生了主要的几种线性结构。 我们使用的List,Set等系列结构都是它的衍生类。
——————————————————————————————
int size();
boolean isEmpty();
boolean contains(Object o);
Object[] toArray();
boolean add(E e);
boolean remove(Object o);
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean removeAll(Collection<?> c);
void clear();
——————————————————————————————
Map
图, 或者称之为表最合适,但是此图非彼图。图是一种基于键值对即Key-Value形式存储的结构,我们经常使用的HashMap即衍生于此。
———————————————————————
int size();
boolean isEmpty();
boolean containsKey(Object key);
boolean containsValue(Object value);
V get(Object key);
V put(K key, V value);
V remove(Object key);
void clear();
...
———————————————————————
Map是一种基于键值对(Key-Value)存储的结构,因此所有操作都是基于键值对操作。我们使用的HashMap, TreeMap, HashSet等都是基于此而来。
List
提供了列表的系列功能, 至于详细的我真不想说了,没有人没用过List是真的,大家都比我熟。它提供的方法与Collection类似,甚至近乎相同。
Set
Set结构有两个重要的特点: 无序性和唯一性。 Set的元素期存入顺序和取出顺序是不一致的,如先后存储ABC,在Set中的元素位置并不一定是ABC,可能是BCA或者其他。 Set的值是唯一的,即Set不允许添加相同值。Set直接继承自Collection, 没有新增方法。
Queue
提供了队列的系列功能,队列是一种先进先出的结构。它提供了以下方法
——————————————————————
boolean add(E e);
boolean offer(E e);
E remove();
E poll();
E element();
E peek();
——————————————————————
队列可能在平时用的很少, 像队列, 栈等结构很多时候可以更方便的解决问题。
结构封装层
实现了公共接口, 对某一类型或某具有相似特征的类型提供基类支持。该层主要包含AbstractMap, AbstractList, AbstractSet等针对底层接口的一些公共的处理,不详细说明。
结构层
这层涉及到具体的数据结构,如List下的ArrayList, LinkedList,Vector; Set下的HashSet, LinkedHashSet,
TreeSet; Map下的HashMap, LinkedHashMap, HashTable, TreeSet等。
《数据结构》系列的目的是理清数据结构的框架 , 了解不同结构的特征,详细讲解不同的具体数据结构以及核心部分的原理。下面将按线性表, 树, 图的大顺序来讲解数据结构;其中顺序表又包含上图中的部分常用的结构。
目录
线性表
顺序表
List系列
Set系列
Queue系列
Vector系列
Stack
Map系列
链表
单链表
双链表
树
树
二叉树
二叉排序树
完全二叉树
红黑树
..
图