2017-2018-1 學習總結目錄: 1 2 3 5 6 7 9 10 11 12
html
- 0. 教材學習內容總結
- 0.1 集合的介紹
- 0.2 棧集合
- 0.3 繼承、多態和泛型
- 0.4 棧的ADT
- 0.5 使用棧:計算後綴表達式
- 0.6 異常
- 0.7 使用數組實現棧
- 0.8 ArrayStack類
- 0.9 將引用做爲鏈
- 0.10 管理鏈表
- 0.11 沒有鏈的元素
- 0.12 使用鏈實現棧
- 0.13 使用
java.util.Stack
類實現棧- 0.14 包
- 分析Java Collections API中的Stack類
- 1. 教材學習中的問題和解決過程
- 1.1 ArrayStack類的expandCapacity方法
- 2. 代碼調試中的問題和解決過程
- 2.1 LinkedStack類中的push方法
集合是 收集 並 組織 其餘對象的對象。java
分類:線性集合(排成一行)、非線性集合(層次、網絡等方式組織)。
【推論】棧集合中元素的添加及刪除都在一端進行,因此 棧集合屬於線性集合。node
集合中元素之間的組織方式取決於:
① 元素加入集合的次序;
② 元素之間的某些固有關係。git
抽象數據類型:(abstract data type)簡稱ADT,其值和操做都沒有被定義。(隱藏細節:集合)算法
數據結構:用來實現集合的基本程序結構集合。數組
Java Collections API:(application programming interface)使用不一樣方式實現的幾類集合的一組類。(包含API)安全
處理元素方式:LIFO(後進先出)網絡
棧頂:元素入棧或出棧的一端。數據結構
在解決問題時,若是要訪問非頂端元素,則不適合使用棧。併發
注意pop和peek操做的區別:pop爲 刪除 棧頂元素,peek爲 查看 棧頂元素。
從單詞上理解,pop有蹦出、離開之意,就至關於彈出了棧中元素;而peek有偷看之意,就至關於查看棧中元素。
類型兼容(多態)、類型檢查(編譯)。
泛型:(保存、操做、管理)直到實例化時才肯定類型的對象。
public interface Stack<T> { // Adds the specified element to the top of the stack. public void push (T element); // Removes and returns the top element from the stack. public T pop(); // Returns a reference to the top element of this stack without removing it. public T peek(); // Returns true if this stack contains no elements and false otherwise. public boolean isEmpty(); // Returns the number of elements in the stack. public int size(); // Returns a string representation of the stack. public String toString(); }
【注意】棧接口是用泛型 T 定義的,實現這個接口時,要用一個具體類型取代 T。
後綴表達式: <操做數> <操做數> <運算符>
後綴表達式不用考慮優先級和括號,比中綴表達式更易於計算。
棧是計算後綴表達式時使用的理想數據結構。
潛在異常:
① 入棧時棧滿;(數據結構)
② 出棧時棧空;(後綴表達式不正確)
③ 掃描完表達式完成計算時棧中的值多於1個。(後綴表達式不正確)
if (!theStack.isEmpty()) element = theStack.pop();
② 當異常發生時,使用 try-catch 語句處理:
try { element = theStack.pop(); } catch (EmptyStackException exception) { System.out.println("No elements available"); }
③ 先設置拋出異常,再自定義一個異常類:
public class EmptyCollectionException extends RuntimeException { /** * Sets up this exception with an appropriate message. * @param collection String representing the name of the collection */ public EmptyCollectionException (String collection) { super ("The " + collection + " is empty."); } }
數組實現的棧將棧底放在下標爲 0 的位置。(順序、連續)
stack = (T[]) (new Object[DEFAULT_CAPACITY]);
/** * Creates a new array to store the contents of this stack with twice the capacity of the old one. */ private void expandCapacity() { T[] larger = (T[]) (new Object[stack.length * 2]); for (int index = 0; index < stack.length; index++) larger[index] = stack[index]; stack = larger; }
//刪除並返回棧頂元素 public T pop() { T result = null; //置空臨時變量的引用 if (!isEmpty()) { //確保棧不空 count--; result = stack[count]; stack[count] = null; } else try { isEmpty(); } catch (EmptyStackException exception) { System.out.println("No elements available"); } return result; } //返回棧頂元素的引用 public T peek() { if (isEmpty()) { try { isEmpty(); } catch (EmptyStackException exception) { System.out.println("No elements available"); } } return stack[count - 1]; } public boolean isEmpty() { return (count == 0); } public int size() { return count; }
鏈式結構:使用對象引用變量創建聯繫。(自指示)
鏈表(對象之間指向關係)
結點(存儲對象)
注意:必須使用一個 單獨的 引用變量指向表中第一個結點。結點的 next 引用爲 null 時表示結束。
數組有固定大小,鏈表沒有容量限制。
訪問元素:必須訪問第一個元素。
插入結點:首先,新節點的 next 指向 current 指向的下一個結點,而後結束當前結點的 next 引用重置指向新節點。(頭插法、尾插法、表中插入)
刪除結點:第1個結點(將表頭引用指向當前第2個結點)、中間節點(前一個的 next 指向當前結點的 next 引用所指向的結點)。
哨兵結點:不用考慮如何處理第1個結點。
//-------------------------------------------------------------------- // Creates an empty stack using the default capacity. //-------------------------------------------------------------------- public LinkedStack() { count = 0; top = null; }
//刪除並返回棧頂元素 public void push(T element) { LinearNode<T> eNode = new LinearNode<>(element); //新元素入棧對應新的對象 eNode.setNext(top); //新結點next引用指向棧頂 top = eNode; count++; } //返回當前棧頂所保存元素的引用 public T peek() throws EmptyStackException { return top.getElement(); } public boolean isEmpty() { return count == 0; } public int size() { return count; }
java.util.Stack
類(擴展)派生於Vector類,可是有些功能違背了棧的假設。包的組織:通常按代碼功能組織爲包(集合,異常)。
使用package XXX
聲明引入的包。
public class Stack<E> extends Vector<E>
體現了其特性,而Vector又擴展了AbstractList類:public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
而該類又繼承了其餘方法,從而使得Stack類實現了List、Collection等接口:
中文版API介紹Stack類說:
它經過五個操做對類 Vector 進行了擴展 ,容許將向量視爲堆棧。它提供了一般的 push 和 pop 操做,以及取堆棧頂點的 peek 方法、測試堆棧是否爲空的 empty 方法、在堆棧中查找項並肯定到堆棧頂距離的 search 方法。
public synchronized int search(Object o) { int i = lastIndexOf(o); if (i >= 0) { return size() - i; } return -1; }
這個方法將對象o做爲一個棧中的元素,先獲取其位置,即最後一次出現(離棧頂最近)時的索引值,最小值爲 1,若是此對象不存在或者檢測對象爲空值,則會返回 -1,舉個例子:
結果體現得很明顯了。
相比起書中實現的棧,除了額外提供了search方法以外,我還發現search、peek 和 pop 方法在聲明時,public後出現了新的關鍵字 synchronized
,它的功能是保證在同一時刻最多隻有一個線程執行該段代碼,就是說當兩個併發線程訪問同一個方法時,一個時間內只能有一個線程獲得執行。另外一個線程必須等待當前線程執行完這個代碼塊之後才能執行該代碼塊。對於synchronized 方法,更詳細的解釋是:
synchronized 方法控制對類成員變量的訪問,每一個類實例都對應一把鎖,每一個 synchronized 方法都必須得到調用該方法的類實例的鎖方能執行,不然所屬線程阻塞,方法一旦執行,就獨佔該鎖,直到從該方法返回時纔將鎖釋放,此後被阻塞的線程方能得到該鎖,從新進入可執行狀態。這種機制確保了同一時刻對於每個類實例,其全部聲明爲 synchronized 的成員函數中至多隻有一個處於可執行狀態。(由於至多隻有一個可以得到該類實例對應的鎖)
這樣一來就能夠避免類成員變量訪問衝突,但若是爲一些時間複雜度高的方法增長對象鎖,就會明顯下降其效率。
public synchronized E pop() { E obj; int len = size(); obj = peek(); removeElementAt(len - 1); return obj; }
其中的`removeElementAt(int index)`方法就是繼承而來: ``` public synchronized void removeElementAt(int index) { modCount++; if (index >= elementCount) { //索引參數越界 throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount); } else if (index < 0) { //索引參數越界 throw new ArrayIndexOutOfBoundsException(index); } int j = elementCount - index - 1; if (j > 0) { System.arraycopy(elementData, index + 1, elementData, index, j); //元素後移 } elementCount--; //元素個數減1 elementData[elementCount] = null; //置空 }
- 再看看peek方法:
public synchronized E peek() {
int i = size();
if (i == 0)
throw new EmptyStackException();
return elementAt(i - 1);
}
這裏又調用了Vector中的`elementAt(int index)`方法: ``` public synchronized E elementAt(int index) { if (index >= elementCount) { throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount); } return elementData(index); }
和removeElementAt(int index)
方法同樣,elementAt(int index)
方法也首先判斷參數是否合法,以後就直接調用elementData(int index)
返回具體的對象值:
E elementData(int index) { return (E) elementData[index]; //保存Stack中的每一個元素 }
synchronized
確保了線程安全,這應該就是其設計中的巧妙之處吧。【問題】:ArrayStack類的expandCapacity方法中的 stack = larger
代碼不太明白它的意思,larger是新定義的泛型數組,其空間是原來 stack 數組的兩倍,直接使用遍歷後的新數組就能夠了,爲何又將新容量的數組賦值給原來的 stack 數組?
private void expandCapacity() { T[] larger = (T[]) (new Object[stack.length * 2]); for (int index = 0; index < stack.length; index++) larger[index] = stack[index]; stack = larger; }
在建立新大小的泛型數組larger後,再將stack中的元素遍歷進去,可是最後又要將larger賦給容量更小的stack。原來我覺得stack是原來的引用,因此將larger數組賦給stack時就認爲是將容量大數組的賦值給了一個容量小的數組,不可以實現。詢問了張旭升以後,發現我對原stack引用理解有誤,在給stack數組賦larger數組的時候,至關於更新了原數組,stack數組在被更新時就已經改變了默認的容量,從而實現擴容效果。
【問題】:在設計LinkedStack類中的push方法時,Junit測試出現紅條,添加的元素並無在刪除時顯示。
public void push(T element) { LinearNode<T> eNode = new LinearNode<>(); eNode.setNext(top); //新結點指向棧頂 top = eNode; count++; }
可是在進行Junit測試時並無成功,pop或者peek方法返回的值一直爲空,在仔細看了第一條賦值語句後,發現我定義的結點中並無傳入push元素,因此就一直保持了棧默認爲空的狀態,因此只須要將傳入的element加入便可:LinearNode<T> eNode = new LinearNode<>(element);
最初出現這個錯誤是由於忽略了泛型結點默認的初始值。
上週國慶放假無考試,因此總結第三週的錯題:
【錯題1】A __________________ search looks through the search pool one element at a time.
A .binary
B .clever
C .insertion
D .selection
E .linear
錯誤緣由:我以爲二分查找每次也是搜索比較一箇中間元素,錯選A。
加深理解:線性查找會逐一在查找池中查找(迭代)一個元素;二分查找每次也在查找池中查找一個元素,可是並非逐一,每次會篩選掉一半。
【注意】look through 在這裏並非瀏覽之意,而是 「逐一檢查」 的意思。
【錯題2】A linear search always requires more comparisons than a binary search.
A .true
B .false
錯誤緣由:考慮狀況不全面,錯選A。
加深理解:若是正在搜索的元素是列表中的第一個元素,那麼線性查找比二分查找須要的比較次數更少。
莫禮鍾本週比第三週的狀態好一點,雖然實驗只完成了第一個和第五個,設計的方法比較簡單,可是都是本身作的。在學習十四章的過程當中,他已經基本掌握瞭如何使用數組實現棧,其中一些比較重要的方法(push、pop)我已經看着他寫了一遍,但願多熟練已掌握的內容,而且再恢復一些學習狀態。
本週算是比較忙的一週了,國慶以後的第一週並不輕鬆,除了運動會的一些瑣事以外,本週的學習任務真心有點多。本週在課堂上咱們又複習了查找與排序的內容,個人掌握狀況還算過關,對於棧、隊列這部份內容我選擇了「先聽課再看書」的方式。到如今爲止,棧的基本內容掌握了,隊列的掌握狀況還差不少,雲班課的測試成績也不算高。本週個人狀態有些降低,主要由於睡眠時間不足致使,下週我會將精力集中回來,而且平衡好完成團隊任務和我的任務的時間。
【附1】教材及考試題中涉及到的英語:
Chinese | English | Chinese | English |
---|---|---|---|
線性集合 | linear collection | 默認值 | default |
非線性集合 | nonlinear collection | 自指示 | self-referential |
封裝 | encapsulate | 動態 | dynamic |
類型兼容 | type compatibility | 堆 | heap |
中綴 | infix | 哨兵結點 | sentinel node |
前綴 | prefix | 虛位結點 | dummy node |
矢量 | vector | 常量 | constant(s) |
操做數 | operand(s) | 指定的 | designated |
優化 | optimize | 空閒存儲區 | free store |
【附2】本週小組博客
代碼行數(新增/累積) | 博客量(新增/累積) | 學習時間(新增/累積) | 重要成長 | |
---|---|---|---|---|
目標 | 5000行 | 30篇 | 400小時 | |
第一週 | 234/234 | 1/28 | 14/14 | 瞭解算法效率、大O符號等理論內容 |
第二週 | 255/489 | 1/29 | 12/26 | 瞭解敏捷的團隊、泛型的使用 |
第三週 | 436/925 | 2/31 | 10/36 | 瞭解一些查找和排序的算法 |
第四周 | 977/1902 | 3/34 | 10/46 | 掌握實現線性結構 |
第五週 | 800/2702 | 2/36 | 12/58 | 掌握實現棧集合 |
計劃學習時間:14小時
實際學習時間:12小時
有效學習時間:5小時
改進狀況:學習內容有所增長,本週個人效率極低,下週必須恢復到以前的狀態,學習時務必心無旁騖。