数据元素之间的相互关系称为结构
数据结构的本质:组织大量数据的方法。如何将现实世界中各种各样的数据放入到内存中,并且如何在内存中操作这些数据,如何评价这些存储方案和操作方法
将现实世界的数据组织成逻辑结构,再把逻辑结构的数据映射到物理结构(比如链表是逻辑线性,物理不连续的)
算法分析:算法运行的时间和空间估计
数据类型指的是一组值和一组对这些值的操作的集合。是组织信息的一种自然方式。
每当遇到逻辑上相关的不同类型的数据时,定义一个抽象数据类型。
抽象数据类型(ADT):一种能够对使用者隐藏数据表示的数据类型。(如用java类来实现抽象数据类型,用一组静态方法实现一个函数库)
常见数据结构:
线性:数组、链表、队列、堆栈、块状数组(数组+链表)、hash表、双端队列、位图(btimap);
树:堆(大顶堆、小顶堆),trie树(字母树or字典树)、后缀树、后缀数组、二叉排序/查找树、B+/B-,AVL树、Treap、红黑树等
图:
栈和队列都可以使用数组或链表实现。栈的操作在表(统称数组和链表)的末尾,队列在表的队尾和队头操作。当队列用数组实现时,保留一个数组以及front和back,以及队列中的元素个数currentSize。使用循环数组实现。
某些数据结构不是为了用户可访问的数据结构而建立的,通常用它们在程序中辅助实现一些算法。
栈、队列和树是抽象数据类型,它们由一些更加基础的数据结构如数组、链表来实现。这些ADT只提供给用户间的的接口,一般仅允许插入和访问或者删除一个数据项。
对于大量的数据,表的线性访问时间太慢。使用树。
堆(优先队列)是允许至少下列两种操作的数据结构:insert(enqueue)以及deleteMin(dequeue)。
实现堆的方法:使用一个简单链表在表头以O(1)执行插入,并遍历该链表以删除最小元,O(N)。或者让链表保持有序地执行插入; 使用二叉查找树,插入和查找的平均时间都是O(logN)。
完全二叉树:被完全填满的二叉树,有可能的例外是在底层,底层上的元素从左到右填入。
当堆不加修饰的出现在优先队列的上下文中时,数据结构为二叉堆。是一颗完全二叉树。完全二叉树的规律,使得它可以用一个数组表示而不需要链表。所以一个堆结构将由一个(Comparable对象的)数组和一个代表当前堆的大小的整数组成。 数组的array[0]空出来。
让操作快速执行的性质是堆序性质。
上滤:将一个元素X插入到堆中,在下一个可用位置创建一个空穴,如果X放在该空穴中而并不破坏堆的序,那么插入完成,否则,把空穴的父节点上的元素移入空穴中,这样,空穴就朝着根的方向上冒一步。
下滤:删除最小元素后,在根节点建立了一个空穴,堆中最后一个元素必须移动到该堆的某个地方。
package binary;
public class BinaryHeap
>{
private int currentSize;
private static final int DEFAULT_CAPACITY = 10;
private Comparable [] array;
public BinaryHeap() {
this(DEFAULT_CAPACITY);
}
public BinaryHeap(int capacity) {
currentSize = 0;
array = new Comparable[capacity + 1];
}
public BinaryHeap(AnyType [] items) {
currentSize = items.length;
array = new Comparable[(currentSize+2)*11/10];
int i = 1;
for(AnyType item : items) {
array[i++] = item;
}
buildHeap();
}
public void insert(AnyType x) {
if(currentSize == array.length - 1) {
enlargeArray(array.length * 2 + 1);
}
int hole = ++currentSize;
for(; hole>1 && x.compareTo((AnyType) array[hole/2]) < 0; hole = hole/2) {
array[hole] = array[hole/2];
}
array[hole] = x;
}
public AnyType findMin() {
if(isEmpty()) {
return null;
}
return (AnyType) array[1];
}
public AnyType deleteMin() {
if(isEmpty()) {
return null;
}
AnyType minItem = findMin();
array[1] = array[currentSize--];
percolateDown(1);
return minItem;
}
public boolean isEmpty() {
return currentSize == 0;
}
public void makeEmpty() {
}
private void percolateDown(int hole) {
int child;
AnyType tmp = (AnyType) array[hole];
for(; hole*2<=currentSize; hole = child) {
child = hole*2;
if(child != currentSize && array[child+1].compareTo(array[child])<0) {
child++;
}
if(array[child].compareTo(tmp) < 0) {
array[hole] = array[child];
} else
break;
}
array[hole] = tmp;
}
private void buildHeap() {
for(int i = currentSize / 2; i > 0; i--) {
percolateDown(i);
}
}
private void enlargeArray(int newSize) {
Comparable [] array1 = new Comparable[newSize];
int i = 0;
for(Comparable item : array) {
array1[i] = item;
i++;
}
array = array1;
}
}
二叉查找树:每个节点X,它的左子树中所有项的值小于X中的项,而它的右子树中所有项的值大于X中的项。
package binary;
public class BinaryHeap
>{
private int currentSize;
private static final int DEFAULT_CAPACITY = 10;
private Comparable [] array;
public BinaryHeap() {
this(DEFAULT_CAPACITY);
}
public BinaryHeap(int capacity) {
currentSize = 0;
array = new Comparable[capacity + 1];
}
public BinaryHeap(AnyType [] items) {
currentSize = items.length;
array = new Comparable[(currentSize+2)*11/10];
int i = 1;
for(AnyType item : items) {
array[i++] = item;
}
buildHeap();
}
public void insert(AnyType x) {
if(currentSize == array.length - 1) {
enlargeArray(array.length * 2 + 1);
}
int hole = ++currentSize;
for(; hole>1 && x.compareTo((AnyType) array[hole/2]) < 0; hole = hole/2) {
array[hole] = array[hole/2];
}
array[hole] = x;
}
public AnyType findMin() {
if(isEmpty()) {
return null;
}
return (AnyType) array[1];
}
public AnyType deleteMin() {
if(isEmpty()) {
return null;
}
AnyType minItem = findMin();
array[1] = array[currentSize--];
percolateDown(1);
return minItem;
}
public boolean isEmpty() {
return currentSize == 0;
}
public void makeEmpty() {
}
private void percolateDown(int hole) {
int child;
AnyType tmp = (AnyType) array[hole];
for(; hole*2<=currentSize; hole = child) {
child = hole*2;
if(child != currentSize && array[child+1].compareTo(array[child])<0) {
child++;
}
if(array[child].compareTo(tmp) < 0) {
array[hole] = array[child];
} else
break;
}
array[hole] = tmp;
}
private void buildHeap() {
for(int i = currentSize / 2; i > 0; i--) {
percolateDown(i);
}
}
private void enlargeArray(int newSize) {
Comparable [] array1 = new Comparable[newSize];
int i = 0;
for(Comparable item : array) {
array1[i] = item;
i++;
}
array = array1;
}
}
AVL树:其每个节点的左子树和右子树的高度最多差1的二叉查找树(空树的高度定义为-1)
package binary;
/*
* 把需要重新平衡的节点叫做t,出现的高度不平衡需要t节点的两棵子树的高度差为2,不平衡出现的情况:
* 1、对t的左儿子的左子树进行一次插入;
* 2、对t的左儿子的右子树进行一次插入;
* 3、对t的右儿子的左子树进行一次插入;
* 4、对t的右儿子的右子树进行一次插入;
* 其中1和4对称,只需要单旋转;2和3对称,需要双旋转。
* 双旋转是先在t的儿子和孙子之间旋转而后再在t和它的新儿子之间旋转的结果
*/
public class AvlNode
> {
AnyType element;
AvlNode
left;
AvlNode
right;
int height;
public AvlNode(AnyType theElement) {
this(theElement, null, null);
}
public AvlNode(AnyType theElement, AvlNode
lt,
AvlNode
rt) { this.element = element; this.left = lt; this.right = rt; this.height = 0; } private int height(AvlNode
t) { return t == null ? -1 : t.height; } private AvlNode
insert(AnyType x, AvlNode
t) { if(t == null) { return new AvlNode
(x); } int comResult = x.compareTo(t.element); if(comResult < 0) { t.left = insert(x, t.left); if(height(t.left) - height(t.right) == 2) { if(x.compareTo(t.left.element) < 0) { t = rotateWithLeftChild(t); } else { t = doubleWithLeftChild(t); } } }else if(comResult > 0) { t.right = insert(x, t.right); if(height(t.right) - height(t.left) == 2) { if(x.compareTo(t.right.element) > 0) { t = rotateWithRightChild(t); } else { t = doubleWithRightChild(t); } } } t.height = Math.max(height(t.left), height(t.right)) + 1; return t; } private AvlNode
rotateWithLeftChild(AvlNode
k2) { AvlNode
k1 = k2.left; k2.left = k1.right; k1.right = k2; k2.height = Math.max(height(k2.left), height(k2.right)) + 1; k1.height = Math.max(height(k1.left), height(k2)) + 1; return k1; } private AvlNode
doubleWithLeftChild(AvlNode
k3) { k3.left = rotateWithRightChild(k3.left); return rotateWithLeftChild(k3); } private AvlNode
rotateWithRightChild(AvlNode
k2) { AvlNode
k1 = k2.right; k2.right = k1.left; k1.left = k2; k2.height = Math.max(height(k2.left), height(k2.right)) + 1; k1.height = Math.max(height(k1.right), height(k2)) + 1; return k1; } private AvlNode
doubleWithRightChild(AvlNode
k3) { k3.right = rotateWithLeftChild(k3.right); return rotateWithRightChild(k3); } }
常见算法:
基本思想:枚举、递归、分治、模拟、贪心、动态规划、剪枝、回溯
图算法:深度优先遍历与广度优先遍历、最短路径、最小生成树、拓扑排序
字符串算法:字符串查找、哈市、算法、KMP算法
排序算法:冒泡、插入、选择、快速排序、归并排序、堆排序、桶排序
动态规划:背包问题、最长公共子序列、最优二分检查树
数论问题:素数问题、整数问题、进制转换、同余模运算
排列组合:排列和组合算法