第5章**数据结构
并查集
二叉树
Treap树
Splay树
线段树
树状数组
竞赛题是对输入的数据进行运算,然后输出结果。因此,编写程序的一个基本问题就是数据处理,包括如何存储输入的数据、如何组织程序中的中间数据等。这个技术就是数据结构。学习数据结构,建立计算思维的基础,是成为合格程序员的基本功。本章讲解一些常用的**数据结构。
数据结构的作用是分析数据、组织数据、存储数据。基本的数据类型有字符和数字,这些数据需要存储在空间中,然后程序按规则读取和处理它们。
数据结构和算法不同,它并不直接解决问题,但是数据结构是算法不可分割的一部分。首先,数据结构把杂乱无章的数据有序地组织起来,逻辑清晰,易于编程处理; 其次,��据结构便于算法**地访问和处理数据,大大减少空间和时间复杂度。
(1) 存储的空间效率。例如一个围棋程序,需要存储棋盘和棋盘上棋子的位置。棋盘可以简单地用一个19×19的二维数组(矩阵)表示。每个棋子是一个坐标,例如W[5][6]表示位于第5行第6列的白棋。这种二维数组是数据结构“图”的一种描述,图是描述点和点之间连接关系的数据结构。棋盘只是一种简单的图,更复杂的图例如地图。地图上有两种元素,即点、点之间直连的道路。地图比棋盘复杂,棋盘的每个点只有上、下、左、右4个相邻的点,而地图上的一个点可能有很多相邻的点。那么如何存储一个地图?可以简单地用一个二维数组,例如有n个点,用一个n×n的二维矩阵表示地图,矩阵上的交叉点(i,j)表示第i点和第j点的连接关系,例如1表示相邻,0表示不相邻。二维矩阵这种数据结构虽然简单、访问速度快,但是用它来存储地图非常浪费空间,因为这是一个稀疏矩阵,其中的交叉点绝大多数等于0,这些等于0的交叉点并不需要存储。一个有10万个点的地图,存储它的二维矩阵大小是100000×100000=10GB。所以,在程序中使用二维矩阵来存储地图是不行的,例如手机上的导航软件,常常有几十万个地点,手机存储卡根本放不下。因此,大地图的存储需要用到更有效率的数据结构,这就是邻接表。
(2) 访问的效率。例如输入一大串个数为n的无序数字,如果直接存储到一个一维数组里面,那么要查找到某个数据,只能一个个试,需要的时间是O(n)。如果先按大小排序然后再查询,处理起来就很有效率。在n个有序的数中找某个数,用折半查找的方法,可以在O(log2n)的时间里找到。
用数据结构存储和处理数据,可以使程序的逻辑更加清晰。
数据结构有以下3个要素
《数据结构与算法分析新视角》,作者周幸妮等,电子工业出版社。。
(1) 数据的逻辑结构: 线性结构(数组、栈、队列、链表)、非线性结构、集合、图等。
(2) 数据的存储结构: 顺序存储(数组)、链式存储、索引存储、散列存储等。
(3) 数据的运算: 初始化、判空、统计、查找、遍历、插入、删除、更新等。
常见的数据结构有数组、链表、栈、队列、树、二叉树、集合、哈希、堆与优先队列、并查集、图、线段树、树状数组等。
在第3章中已经介绍了基本的数据结构
《数据结构(STL框架)》,作者王晓东,清华大学出版社。——栈、队列、链表,本章继续讲解一些常用的**数据结构,包括并查集、二叉树、线段树、树状数组。
5.1并查集
并查集(Disjoint Set)是一种非常精巧而且实用的数据结构,它主要用于处理一些不相交集合的合并问题。经典的例子有连通子图、*小生成树Kruskal算法
参考本书的“10.10.2 kruskal算法”。和*近公共祖先(Lowest Common Ancestors,LCA)等。
通常用“帮派”的例子来说明并查集的应用背景。在一个城市中有n个人,他们分成不同的帮派; 给出一些人的关系,例如1号、2号是朋友,1号、3号也是朋友,那么他们都属于一个帮派; 在分析完所有的朋友关系之后,问有多少帮派,每人属于哪个帮派。给出的n可能是106的。
读者可以先思考暴力的方法以及复杂度。如果用并查集实现,不仅代码很简单,而且复杂度可以达到O(log2n)。
并查集: 将编号分别为1~n的n个对象划分为不相交集合,在每个集合中,选择其中某个元素代表所在集合。在这个集合中,并查集的操作有初始化、合并、查找。