數據結構與算法學習筆記以後進先出的「桶」

前言

棧最爲一種的經常使用的數據結構,用「桶」來形容最合適不過;今天咱們就來學習一下html

正文

1、棧的定義?


1.「後進先出,先進後出」的數據結構。
2.從操做特性來看,是一種「操做受限」的線性表,只能夠在一端插入和刪除數據。算法

 

2、爲何須要棧?

 

1.任何數據結構都是對特定應用場景的抽象,棧是一種操做受限的數據結構,其操做特性用數組和鏈表都可實現,但卻暴露太多的操做接口,使用時容易出錯;數組


2.當某個數據集合只涉及在一端插入和刪除數據,且知足後進者先出,先進者後出的操做特性時,咱們應該首選棧這種數據結構瀏覽器

 

3、如何實現棧?

 棧能夠用數組,鏈表來實現網絡

1.以數組爲例

空間複雜度爲O(1)數據結構

時間複雜度大多數爲O(1),特殊狀況自動擴容拷貝原數組時爲O(n);ide

均攤時間複雜度接近於O(1);函數

// 基於數組實現的順序棧
public class ArrayStack { private String[] items;  // 數組
  private int count;       // 棧中元素個數
  private int n;           // 棧的大小 // 初始化數組,申請一個大小爲 n 的數組空間
  public ArrayStack(int n) { this.items = new String[n]; this.n = n; this.count = 0; } // 入棧操做
  public boolean push(String item) { // 數組空間不夠了,直接返回 false,入棧失敗。
    if (count == n) return false; // 將 item 放到下標爲 count 的位置,而且 count 加一
    items[count] = item; ++count; return true; } // 出棧操做
  public String pop() { // 棧爲空,則直接返回 null
    if (count == 0) return null; // 返回下標爲 count-1 的數組元素,而且棧中元素個數 count 減一
    String tmp = items[count-1]; --count; return tmp; } }

 (代碼來自於網絡,若有侵權請告知我刪除)post

2.以鏈表爲例(網上找的)

空間複雜度爲O(1)性能

時間複雜度大多數爲O(1)

public class StackOfLinked<Item> implements Iterable<Item> { //定義一個內部類,就能夠直接使用類型參數
private class Node{ Item item; Node next; } private Node first; private int N; //構造器
public StackOfLinked(){} //添加
public void push(Item item){ Node oldfirst = first; first = new Node(); first.item = item; first.next = oldfirst; N++; } //刪除
public Item pop(){ Item item = first.item; first = first.next; N--; return item; } //是否爲空
public boolean isEmpty(){ return N == 0; } //元素數量
public int size(){ return N; } //返回棧中最近添加的元素而不刪除它
public Item peek(){ return first.item; } @Override public Iterator<Item> iterator() { return new LinkedIterator(); } //內部類:迭代器
class LinkedIterator implements Iterator{ int i = N; Node t = first; @Override public boolean hasNext() { return i > 0; } @Override public Item next() { Item item = (Item) t.item; t = t.next; i--; return item; } } }

(代碼來自於網絡,若有侵權請告知我刪除)

4、棧的應用

1.函數調用中的應用

操做系統給每一個線程分配了一塊獨立的內存空間,這塊內存被組織成「棧」這種結構,用來存儲函數調用時的臨時變量。每進入一個函數,就會將其中的臨時變量做爲棧幀入棧,當被調用函數執行完成,返回以後,將這個函數對應的棧幀出棧。

 

2.在表達式求值中的應用(好比:34+13*9+44-12/3)

利用兩個棧,一個用來保存操做數,一個用來保存運算符。咱們從左向右遍歷表達式,當遇到數字,咱們就直接壓入操做數棧;當遇到運算符,就與運算符棧的棧頂元素進行比較,若比運算符棧頂元素優先級高,就將當前運算符壓入棧,若比運算符棧頂元素的優先級低或者相同,從運算符棧中取出棧頂運算符,從操做數棧頂取出2個操做數,而後進行計算,把計算完的結果壓入操做數棧,繼續比較。

  (圖片來自於王爭)

3.棧在括號匹配中的應用(好比:{}{[()]()})

用棧保存爲匹配的左括號,從左到右一次掃描字符串,當掃描到左括號時,則將其壓入棧中;當掃描到右括號時,從棧頂取出一個左括號,若是能匹配上,則繼續掃描剩下的字符串。若是掃描過程當中,遇到不能配對的右括號,或者棧中沒有數據,則說明爲非法格式。
當全部的括號都掃描完成以後,若是棧爲空,則說明字符串爲合法格式;不然,說明未匹配的左括號爲非法格式。

 

4.如何實現瀏覽器的前進後退功能?


咱們使用兩個棧X和Y,咱們把首次瀏覽的頁面依次壓如棧X,當點擊後退按鈕時,再依次從棧X中出棧,並將出棧的數據一次放入Y棧。當點擊前進按鈕時,咱們依次從棧Y中取出數據,放入棧X中。當棧X中沒有數據時,說明沒有頁面能夠繼續後退瀏覽了。當Y棧沒有數據,那就說明沒有頁面能夠點擊前進瀏覽了。

(圖片來自於王爭)

 

5、兩個問題

1. 咱們在講棧的應用時,講到用函數調用棧來保存臨時變量,爲何函數調用要用「棧」來保存臨時變量呢?用其餘數據結構不行嗎?


答:由於函數調用的執行順序符合後進者先出,先進者後出的特色。

函數調用中常常嵌套,栗子:A調用B,B又調用C,那麼就須要先把C執行完,結果賦值給B中的臨時變量,B的執行結果再賦值給A的臨時變量,嵌套越深的函數越須要被先執行,這樣恰好符合棧的特色,所以每次遇到函數調用,只須要壓棧,最後依次從棧頂彈出依次執行便可,根據數據結構是特定應用場景的抽象的原則,咱們優先考慮棧結構。

 

2.咱們都知道,JVM 內存管理中有個「堆棧」的概念。棧內存用來存儲局部變量和方法調用,堆內存用來存儲 Java 中的對象。那 JVM 裏面的「棧」跟咱們這裏說的「棧」是否是一回事呢?若是不是,那它爲何又叫做「棧」呢?

 

答:內存中的堆棧和數據結構堆棧不是一個概念,能夠說內存中的堆棧是真實存在的物理區,數據結構中的堆棧是抽象的數據存儲結構。
內存空間在邏輯上分爲三部分:代碼區、靜態數據區和動態數據區,動態數據區又分爲棧區和堆區。
代碼區:存儲方法體的二進制代碼。高級調度(做業調度)、中級調度(內存調度)、低級調度(進程調度)控制代碼區執行代碼的切換。
靜態數據區:存儲全局變量、靜態變量、常量,常量包括final修飾的常量和String常量。系統自動分配和回收。
棧區:存儲運行方法的形參、局部變量、返回值。由系統自動分配和回收。
堆區:new一個對象的引用或地址存儲在棧區,指向該對象存儲在堆區中的真實數據。

 

相關文章

數據結構與算法學習筆記之寫鏈表代碼的正確姿式(下)

數據結構與算法學習筆記之 提升讀取性能的鏈表(上)

數據結構與算法學習筆記之 從0編號的數組

 

 

以上內容爲我的的學習筆記,僅做爲學習交流之用。

歡迎你們關注公衆號,不定時乾貨,只作有價值的輸出

做者:Dawnzhang 
出處:http://www.javashuo.com/article/p-hogycnsd-gb.html

版權:本文版權歸做者轉載:歡迎轉載,但未經做者贊成,必須保留此段聲明;必須在文章中給出原文鏈接;不然必究法律責任

相關文章
相關標籤/搜索