brianway

# 常见数据结构(一)-栈,队列,堆,哈希表

[TOC]

## Stacks(栈)

LIFO(后进先出):last in first out.

``````public class LinkedStackOfStrings {
private Node first = null;

private class Node {
String item;
Node next;
}

public boolean isEmpty() {
return first == null;
}

public void push(String item) {
Node oldfirst = first;
first = new Node();
first.item = item;
first.next = oldfirst;
}

public String pop() {
String item = first.item;
first = first.next;
return item;
}
}``````
• 使用数组实现

``````public class FixedCapacityStackOfStrings {
private String[] s;
private int N = 0;

public FixedCapacityStackOfStrings(int capacity) {
s = new String[capacity];
}

public boolean isEmpty() {
return N == 0;
}

public void push(String item) {
s[N++] = item;
}

public String pop() {
String item = s[--N];
s[N] = null;
return item;
}
}``````

1. 从空栈pop会抛出异常

2. 插入元素过多会超出数组上界

• N:1 array access per push

• (2 + 4 + 8 + ... + N):k array accesses to double to size k (ignoring cost to create new array)

## Queues(队列)

FIFO(先进先出):first in first out.

``````public class LinkedQueueOfStrings {
private Node first, last;

private class Node {
/* same as in StackOfStrings */
}

public boolean isEmpty() {
return first == null;
}

public void enqueue(String item) {
Node oldlast = last;
last = new Node();
last.item = item;
last.next = null;
if (isEmpty()) {
first = last;
} else {
oldlast.next = last;
}
}

public String dequeue() {
String item = first.item;
first = first.next;
if (isEmpty()) last = null;
return item;
}
}``````
• 使用数组实现

``````・Use array q[] to store items in queue.
・enqueue(): add new item at q[tail].
・Update head and tail modulo the capacity.

## Priority Queues

Collections. Insert and delete items.

• Stack. Remove the item most recently added.

• Queue. Remove the item least recently added. Randomized queue. Remove a random item.

• Priority queue. Remove the largest (or smallest) item.

unordered array 实现

``````public class UnorderedMaxPQ<Key extends Comparable<Key>> {
private Key[] pq;   // pq[i] = ith element on pq
private int N;      // number of elements on pq

public UnorderedMaxPQ(int capacity) {
pq = (Key[]) new Comparable[capacity];
}

public boolean isEmpty() {
return N == 0;
}

public void insert(Key x) {
pq[N++] = x;
}

public Key delMax() {
int max = 0;
for (int i = 1; i < N; i++)
if (less(max, i)) max = i;

exch(max, N - 1);
return pq[--N];
}
}``````

## Binary Heaps(二叉堆)

• Parent's key no smaller than children's keys

• Indices start at 1.

• Parent of node at k is at k/2.

• Children of node at k are at 2k and 2k+1.

### 上浮和下沉

1. 子节点的键值变为比父节点大

2. 父节点的键值变为比子节点（一个或两个）小

• 上浮：子节点key比父节点大

• Exchange key in child with key in parent.

• Repeat until heap order restored.

• 下沉：父节点key比子节点（one or both）小

• Exchange key in parent with key in larger child.

• Repeat until heap order restored

``````/* 上浮 */
private void swim(int k) {
while (k > 1 && less(k / 2, k)) {
exch(k, k / 2);
k = k / 2;
}
}

/* 下沉 */
private void sink(int k) {
while (2 * k <= N) {
int j = 2 * k;
if (j < N && less(j, j + 1)) j++;
if (!less(k, j)) break;
exch(k, j);
k = j;

}
}``````

### 插入和删除

• 插入：二叉堆的插入操作比较简单，把节点加在数组尾部，然后上浮即可。

• 删除最大：二叉堆的删除则是把根节点和末尾的节点交换，然后下沉该节点即可。

``````/* 插入 */
public void insert(Key x){
pq[++N] = x;
swim(N);
}

/* 删除 */
public Key delMax(){
Key max = pq[1];
exch(1, N--);
sink(1);
pq[N+1]=null;
return max;
}``````

## Symbol Tables

• Reflexive: x.equals(x) is true.

• Symmetric: x.equals(y) iff y.equals(x).

• Transitive: if x.equals(y) and y.equals(z), then x.equals(z).

• Non-null: x.equals(null) is false.

• Optimization for reference equality.

• Check against null.

• Check that two objects are of the same type and cast.

• Compare each significant field:

• if field is a primitive type, use ==

• if field is an object, use equals().[apply rule recursively]

• if field is an array, apply to each entry.[alternatively, use Arrays.equals(a, b) or Arrays.deepEquals(a, b),but not a.equals(b)]

1. 无序链表：Maintain an (unordered) linked list of key-value pairs.

2. 有序数组：Maintain an ordered array of key-value pairs.

## Hash Tables(哈希表)

• Hash code:An int between -2^31 and 2^31 - 1.

• Hash function. An int between 0 and M - 1 (for use as array index).

``````//这里hashCode可能为负，且-2^31取绝对值会溢出，所以要“位与”
private int hash(Key key){
return (key.hashCode() & 0x7fffffff) % M;
}``````

`````` public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;

for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}``````

hash code design."Standard" recipe for user-defined types：

• Combine each significant field using the 31x + y rule.

• If field is a primitive type, use wrapper type hashCode().

• If field is null, return 0.

• If field is a reference type, use hashCode().[applies rule recursively]

• If field is an array, apply to each entry.[or use Arrays.deepHashCode()]

• separate chaining

• linear probing

### separate chaining

Use an array of M < N linked lists.

• 哈希：将key映射到0 ~ M-1 之间的一个整数i

• 插入：将值插在第i个链的前端

• 查找：只需遍历第i个链

### linear probing

• 哈希：将key映射到 0 ~ M-1 之间的一个整数i

• 插入：如果数组索引为 i 的位置为空，则把值放入，否则依次尝试 i+1,i+2等索引，直到有空的

• 查找：先找索引 i，如果被占用且没匹配，则依次尝试i+1, i+2,等等

##### brianway
live for show,一个菜鸟的成长之路

1.4k 声望
447 粉丝
0 条评论