1. 程式人生 > >常見資料結構(一)-棧,佇列,堆,雜湊表

常見資料結構(一)-棧,佇列,堆,雜湊表

轉載:https://blog.csdn.net/u013063153/article/details/54667361?locationNum=8&fps=1

寫在前面

Stacks(棧)

LIFO(後進先出):last in first out.

  • 使用linked-list實現

儲存指向第一個節點的指標,每次從前面插入/刪除節點。

以字串棧為例,示例程式碼:


     
  1. public class LinkedStackOfStrings {
  2. private
    Node first = null ;
  3. private class Node {
  4. String item ;
  5. Node next ;
  6. }
  7. public boolean isEmpty () {
  8. return first == null ;
  9. }
  10. public void push ( String item ) {
  11. Node oldfirst = first ;
  12. first = new Node ();
  13. first . item = item ;
  14. first . next = oldfirst ;
  15. }
  16. public String pop () {
  17. String item = first . item ;
  18. first = first . next ;
  19. return item ;
  20. }
  21. }
  • 使用陣列實現

使用陣列來儲存棧中的項


     
  1. public class FixedCapacityStackOfStrings {
  2. private String [] s ;
  3. private int N = 0 ;
  4. public FixedCapacityStackOfStrings ( int capacity ) {
  5. s = new String [ capacity ];
  6. }
  7. public boolean isEmpty () {
  8. return N == 0 ;
  9. }
  10. public void push ( String item ) {
  11. s [ N ++] = item ;
  12. }
  13. public String pop () {
  14. String item = s [-- N ];
  15. s [ N ] = null ;
  16. return item ;
  17. }
  18. }

上面的實現會有幾個問題:

  1. 從空棧pop會丟擲異常
  2. 插入元素過多會超出陣列上界

這裡重點解決第二個問題,resizing arrays.一個可行的方案是: 當陣列滿的時候,陣列大小加倍;當陣列是1/4滿的時候,陣列大小減半。 這裡不是在陣列半滿時削減size,這樣可以避免陣列在將滿未滿的臨界點多次push-pop-push-pop操作造成大量的陣列拷貝操作。

插入N個元素,N + (2 + 4 + 8 + ... + N) ~ 3N

  • N:1 array access per push
  • (2 + 4 + 8 + … + N):k array accesses to double to size k (ignoring cost to create new array)

由於resize操作不是經常發生,所以均攤下來,平均每次push/pop操作的還是常量時間(constant amortized time).

Queues(佇列)

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

  • 使用linked-list實現

儲存指向首尾節點的指標,每次從連結串列尾插入,從連結串列頭刪除。


     
  1. public class LinkedQueueOfStrings {
  2. private Node first , last ;
  3. private class Node {
  4. /* same as in StackOfStrings */
  5. }
  6. public boolean isEmpty () {
  7. return first == null ;
  8. }
  9. public void enqueue ( String item ) {
  10. Node oldlast = last ;
  11. last = new Node ();
  12. last . item = item ;
  13. last . next = null ;
  14. if ( isEmpty ()) {
  15. first = last ;
  16. } else {
  17. oldlast . next = last ;
  18. }
  19. }
  20. public String dequeue () {
  21. String item = first . item ;
  22. first = first . next ;
  23. if ( isEmpty ()) last = null ;
  24. return item ;
  25. }
  26. }
  • 使用陣列實現

     
  1. ・Use array q[] to store items in queue.
  2. ・enqueue(): add new item at q[tail].
  3. ・dequeue(): remove item from q[head].
  4. ・Update head and tail modulo the capacity.
  5. ・Add resizing array.

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 實現


     
  1. public class UnorderedMaxPQ<Key extends Comparable<Key>> {
  2. private Key [] pq ; // pq[i] = ith element on pq
  3. private int N ; // number of elements on pq
  4. public UnorderedMaxPQ ( int capacity ) {
  5. pq = ( Key []) new Comparable [ capacity ];
  6. }
  7. public boolean isEmpty () {
  8. return N == 0 ;
  9. }
  10. public void insert ( Key x ) {
  11. pq [ N ++] = x ;
  12. }
  13. public Key delMax () {
  14. int max = 0 ;
  15. for ( int i = 1 ; i < N ; i ++)
  16. if ( less ( max , i )) max = i ;
  17. exch ( max , N - 1 );
  18. return pq [-- N ];
  19. }
  20. }

Binary Heaps(二叉堆)

使用陣列來表示一個二叉堆。根節點索引從1開始。索引對應在樹中的位置,最大的鍵值是a[1],同時也是二叉樹的根節點。

  • 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

     
  1. /* 上浮 */
  2. private void swim ( int k ) {
  3. while ( k > 1 && less ( k / 2 , k )) {
  4. exch ( k , k / 2 );
  5. k = k / 2 ;
  6. }
  7. }
  8. /* 下沉 */
  9. private void sink ( int k ) {
  10. while ( 2 * k <= N ) {
  11. int j = 2 * k ;
  12. if ( j < N && less ( j , j + 1 )) j ++;
  13. if (! less ( k , j )) break ;
  14. exch ( k , j );
  15. k =