第一章 概述
(1)什么是数据结构和算法
数据结构是对内存或者是磁盘上数据的一种安排,算法是对这些数据进行处理。
(2)数据结构的应用
1.现实世界数据存储。如档案,航班信息
2.程序员工具。使用堆,栈来优化一些操作
3.建模。图可以模拟城市之间的航线
(3)数据结构的特性
1.数组 适合随机存取(根据公式),如果有序,折半查找快。插入,删除效率低,大小固定,栈中分配空间。
2.链表 插入,删除效率高,查找快(需要从头遍历),堆中分配空间。
3.栈 提供先进后出方式存储,存储其它项很慢。
4.队列 提供先进先出方式存储,存储其它项很慢。
5.二叉树 查找、删除、插入都很快(如果树平衡) 删除操作复杂
6.红-黑树 查找、删除、插入都很快(如果树平衡) 删除操作复杂
7.2-3-4树 查找、删除、插入都很快(如果树平衡) 删除操作复杂
8.哈希表 如果知道关键字,存取是极其快的,查找也快
9.图 对现实建模
10.堆 插入删除快,对最大数据项的存取很快,对其它数据项存储慢
第二章 数组
(1) 基本定义
int[] intArray=new int[100];
查找:线性查找和二分查找(折半)对于与无序数组和有序数组,在有序数组中如果设置了不允许重复,提高了
查找速度,但降低了插入速度(每次插入都需要比较).对于小数目比如10个数,现象查找需要比较N/2=5次,
二分查找4次,差别不大。对于大数据,二分查找就表现极为优秀。
eg:BinarySearch.java
(2) 大O表示法
描述算法的时间T和数据项的个数联系的比较(无序数组的插入是唯一和数据项的个数无关的算法),
无序数组插入 T=K K等于微处理器,编译程序生成程序代码的效率等一些因素的总和。
线性查找 T=K*N/2。
二分查找 T=K*log2(N)。
大O表示法是省略了常数K。O(1) O(N/2) O(long2(N))
第三章 二叉树
(1) 二叉树结合了另外两种数据结构的优点:一种是有序数组,另一种是链表。在树中查找数据项的速度和在有序数组
中查找一样快,并且插入数据项和删除数据项的速度和链表一样。
(2) 二叉树的表示方法,在二叉树中节点代表一些实体,而节点和节点之间的关系,用引用来表示。二叉树是指,在树中
最多只有两个子节点。二叉搜索树是指一个节点的左节点的关键字值小于这个节点,右节点的关键字大于或等于这个
节点。
(3) 树的一些基本概念
1) 路径:从一个节点到另一个节点,所经过节点的顺序排列
2) 访问:访问节点是指查看节点信息或者显示节点,如果仅仅是在路径上从一个节点到另一个节点,不算访问
3) 遍历:遍历树是遵循某种特定的顺序访问树中所有的节点
4) 层:一个节点的层数,是从根节点到这个节点有多少代
5) 根: 一颗树只有一个根,从根到任何一个节点有且只有一条路径,否则就不是树。
二叉树搜索树:
优点:可以快速查找到一个给定关键字的数据项,并且可以快速
的插入和删除数据项。
缺点:但是如果数据项插入是随机的,执行效果会非常好
但如果插入是有序,或者是逆序,速度就很慢(非平衡树)
第四章 哈希表
(1)核心概念:哈希表是基于数组的,它是把关键字转换为数组下标,在哈希表中通过哈希函数来实现。
比如单词melioration 通过哈希函数得到一个整数值,这个整数值就是数组的下标,而查找是
就很容易了,array[下标] 就是这个单词的值。
(2)冲突:有可能melioration通过哈希函数得到的值和另外一个单词得到的值一样,如demystify所得到的哈希值是一样的,就会产生冲突。冲突解决的方法,1.开放地址法:因为
数组的大小两倍需要存储的数据量,所以数组中有大量的空位,产生冲突时,只需要放在一个空位就可以了。2.链地址法:创建一个存储单词链表的数组,当产生冲突时,新的数
据项直接
放入数组下标所指向的链表中。
(3)开放地址法:线性探索,二次探索,再哈希法。线性探索是沿着数组的下标一步一步顺序查找空白单元
重写hashCode()规则
public int hashCode() {
int result = 17; //任意素数
result = 31*result +c1; //c1,c2是什么看下文解释
result = 31*result +c2;
return result;
}
其中c1,c2是我们生成的你要计算在内的字段的代码,生成规则如下:
如果字段是boolean 计算为(f?1:0);
如果字段是byte,char,short,int则计算为 (int)f;
如果字段是long 计算为 (int)(f^(f>>32));
如果字段是float 计算为 Float.floatToLongBits(f);
如果字段是一个引用对象,那么直接调用对象的hashCode方法,如果需要判空,可以加上如果为空就返回0;
如果字段是一个数组则需要遍历所有元素,按上面几种方法计算;
eg:
public class Unit{
private short ashort;
private char achar;
private byte abyte;
private boolean abool;
private long along;
private float afloat;
private double adouble;
private Unit aObject;
private int[] ints;
private Unit[] units;
public int hashCode() {
int result = 17;
result = 37 * result + (int) ashort;
result = 37 * result + (int) achar;
result = 37 * result + (int) abyte;
result = 37 * result + (abool ? 0 : 1);
result = 37 * result + (int) (along ^ (along >>> 32));
result = 37 * result + Float.floatToIntBits(afloat);
long tolong = Double.doubleToLongBits(adouble);
result = 37 * result + (int) (tolong ^ (tolong >>> 32));
result = 37 * result + aObject.hashCode();
result = 37 * result + intsHashCode(ints);
result = 37 * result + unitsHashCode(units);
return result;
}
private int intsHashCode(int[] aints) {
int result = 17;
for (int i = 0; i < aints.length; i++)
result = 37 * result + aints[i];
return result;
}
private int unitsHashCode(Unit[] aUnits) {
int result = 17;
for (int i = 0; i < aUnits.length; i++)
result = 37 * result + aUnits[i].hashCode();
return result;
}
}
第五章 堆
堆是一颗二叉树。在优先级队列中虽然删除的时间复杂度O(1) 但插入的时间复杂度O(N)。而堆它在插入和删除的时间复杂度都是O(logN)
特性:(1) 除最后一层外从左到右都是满的,即是一颗完全二叉树。
(2) 用数组来来存储各个节点,
(3) 堆中的每个节点都满足堆的条件,也就是每个节点的关键字值都大于这个字节点的关键字值。
第六章 图
图主要是由顶点和边组成,任何两个顶点之间可达,则称之为连通图。在图的程序设计中,顶点的集合存储在数组中,而边的存储方式有邻接矩阵和邻接表组成。
邻接矩阵其实就是一个二维数组,数据项表示两个顶点之间是否存在边,如果有N个顶点,则邻接矩阵就有N*N的二维数组。
/**
* @Class Graph
* @Description 图的基本算法
* @Company OpenData
* @author Chenlly
* @Date 2009-03-22
* @version 1.0
*/
//顶点类
class Vertex {
public char label;
public boolean wasVisited;
public Vertex(char label){
this.label = label;
}
}
public class Graph {
//定义顶点的最大个数
private final static int MAX_VERTEX = 20;
//图中当前的顶点个数
private int nVertex;
//顶多列表
private Vertex vertexList[];
//定义边,两个顶点如果直通边(邻接顶点)则为1,如果没有则为0
private int adjMat[][];
public Graph(){
vertextList = new Vertex[MAX_VERTEX];
adjMat[][] = new int[MAX_VERTEX][MAX_VERTEX];
for (int i = 0; i < MAX_VERTEX; i++){
for (int j = 0; j < MAX_VERTEX; j++){
adjMat[i][j] = 0;
}
}
}
//向图中添加顶点
public addVertex(char label){
vertextList[nVertex++] = new Vertex(label);
}
//添加边
public void addEdge(int start,int end){
adjMat[start][end] = 1;
adjMat[end][start] = 1;
}
}