大話資料結構(五)——棧的兩種java實現方式
阿新 • • 發佈:2018-11-10
在我們生活當中經常會看到這樣一種操作,比如我們往一個空羽毛球盒子裡面放羽毛球(個人比較喜歡羽毛球,嘿嘿),放完後再將羽毛球一個一個取出的時候會發現,最先放進去的羽毛球往往最後才取出來,相反,最後放入的羽毛球往往最先取出。這個例子形象的說明了棧的操作方式,下面我們來看看什麼是棧,以及棧的一些操作。
那麼什麼是棧呢?棧就是限定在表尾進行插入和刪除操作的線性表。我們將允許插入和刪除的一端稱為棧頂(top),而另一端就稱之為棧底(bottom),當棧中無任何資料元素時稱作空棧。由上面的例子可以知道羽毛球的放入和取出為後進先出的,那麼棧與之相同,也是後進先出的(LIFO)結構。
棧是一個線性表,它具有線性關係,即前驅後繼的關係。由於棧限定了線性表插入和刪除的位置,所以棧底也是固定的。線上性表中表頭是棧底,表我是棧頂。最先入棧的只能在棧底。下面我們來看看棧的兩種操作——進棧和出棧:
進棧(push):棧的插入操作,也可稱為壓棧或者入棧,操作過程就類似上述的放羽毛球的過程。
出棧(pop):棧的刪除操作,也可稱為彈棧,操作過程就類似上述的取羽毛球的過程。
在表尾進行插入和刪除操作的線性表
我們可以看看圖片理解理解:
上面也說到了棧是一種線性表,而線性表有順序儲存結構和鏈式儲存結構,所以棧的實現方式也有兩種,即順序棧和鏈式棧。
首先我們來看看順序棧
package ArrayStack;
import java.util.Arrays;
/**
* Created by jiangxs on 17-5-24.
*/
public class ArrayStack<T> {
private final int DEFAULT_SIZE = 10;//設定預設尺寸
private int capacity;//儲存當前陣列長度
private int addCapacity;//設定當超出原陣列長度時增加的長度
private Object[] elements;//初始化順序棧陣列
private int size;//儲存順序棧中元素的個數
//建立預設長度的空順序棧
public ArrayStack(){
capacity = DEFAULT_SIZE;
elements = new Object[capacity];
}
//建立指定長度的空順序棧
public ArrayStack(int capacity){
this.capacity = capacity;
elements = new Object[capacity];
}
/**
* 建立指定長度的空順序棧,並指定超出陣列範圍後的增量
* @param capacity 設定指定長度
* @param addCapacity 設定增量
*/
public ArrayStack(int capacity,int addCapacity){
this.capacity = capacity;
this.addCapacity = addCapacity;
elements = new Object[capacity];
}
//獲取順序棧的長度
public int getSize(){
return size;
}
//判斷順序棧是否為空棧
public boolean isEmpty(){
return size == 0;
}
//確保陣列長度,如果超出就進行拓展
private void ensureCapacity(int inputCapacity){
//如果輸入的陣列長度大於原有陣列的長度
if (inputCapacity > capacity) {
//若果有設定陣列增量
if (addCapacity > 0)
while (inputCapacity > capacity)
//按照增量擴容,直到大於所需的陣列容量
capacity += inputCapacity;
//如果未設定陣列增量
else
while (inputCapacity > capacity)
//將capacity左移,使其為大於所需容量
capacity <<= 1;
//擴容後,將原陣列複製到新陣列中
elements = Arrays.copyOf(elements, capacity);
}
}
//進棧
public void push(T element){
//確保陣列長度
ensureCapacity(size+1);
//元素進棧
elements[size++] = element;
}
//出棧
//同時返回彈出的元素
public T pop(){
//如果是空棧
if (isEmpty())
return null;
T element = (T) elements[size-1];
//釋放棧頂元素並將長度減一
elements[--size] = null;
return element;
}
//獲取棧頂元素
public T getTop(){
return (T)elements[size-1];
}
//清空順序棧
public void clear(){
for (int i = 0;i<size;i++)
elements[i] = null;
size = 0;
}
public String toString(){
if (isEmpty())
return "[]";
else {
StringBuilder sb = new StringBuilder("[");
for (int i = size-1;i >= 0;i--)
sb.append(elements[i].toString()+" ");
sb.append("]");
int len = sb.length();
return sb.delete(len-2,len-1).toString();
}
}
}
測試程式碼:
package ArrayStack;
/**
* Created by jiangxs on 17-5-24.
*/
public class ArrayStackTest {
public static void main(String[] args) {
ArrayStack<String> ll = new ArrayStack<String>();
System.out.println("原棧中的元素: "+ll);
System.out.println("----------進棧啦----------");
//壓棧
ll.push("haha");
ll.push("hehe");
ll.push("xixi");
ll.push("hiahia");
ll.push("heihei");
System.out.println("壓棧後棧中所含元素: "+ll);
//獲取棧頂元素
System.out.println("棧頂元素為: "+ll.getTop());
//獲取棧中元素個數
System.out.println("當前棧中元素個數為: "+ll.getSize());
//出棧
System.out.println("----------出棧啦----------");
ll.pop();
System.out.println("出棧後棧中所含元素: "+ll);
//獲取棧頂元素
System.out.println("棧頂元素為: "+ll.getTop());
//獲取棧中元素個數
System.out.println("當前棧中元素個數為: "+ll.getSize());
}
}
測試結果
原棧中的元素: []
----------進棧啦----------
壓棧後棧中所含元素: [heihei hiahia xixi hehe haha]
棧頂元素為: heihei
當前棧中元素個數為: 5
----------出棧啦----------
出棧後棧中所含元素: [hiahia xixi hehe haha]
棧頂元素為: hiahia
當前棧中元素個數為: 4
Process finished with exit code 0
下面我們再來看看鏈棧:
鏈棧的入棧操作如下圖:
鏈棧的出棧如下圖:
下面我們來看看鏈棧的程式碼實現
鏈棧LinkStack
其中棧頂為結點top,類中包含入棧,出棧,清空等操作
package LinkListStack;
/**
* Created by jiangxs on 17-5-24.
*/
public class LinkListStack<T> {
//定義一個內部類Node代表單鏈表的結點
private class Node{
private T element;
private Node next;
//初始化空構造器
public Node(){}
//初始化含引數構造器
public Node(T element,Node next){
this.element = element;
this.next = next;
}
}
private Node top;//存放棧頂結點
private int size;//存放棧中結點數
//初始化空棧
public LinkListStack(){}
//獲取棧長度
public int getSize(){
return size;
}
//判斷棧是否為空棧
public boolean isEmpty(){
return size == 0;
}
//進棧
public void push(T element){
//進棧時,新結點的後驅指標next指向舊top
Node newNode = new Node(element,top);
//進來的新結點更新為top
top = newNode;
size++;
}
//出棧
//返回彈出的元素
public T pop(){
//如果彈出時棧為空則返回空
if (isEmpty())
return null;
//用一個結點儲存原頭結點
Node p = top;
//將現在的頭結點更新為原結點的下一個結點
top = top.next;
//將原頭結點釋放
p.next = null;
size--;
return p.element;
}
//獲取棧頂元素
public T getTop(){
//如果為空棧則返回空
if (isEmpty())
return null;
return top.element;
}
//清空棧
public void clear(){
top = null;
size = 0;
}
public String toString(){
if (isEmpty())
return "[]";
else {
StringBuilder sb = new StringBuilder("[");
for (Node current = top;current != null;current = current.next)
sb.append(current.element.toString()+"->");
sb.append("]");
int len = sb.length();
return sb.delete(len-3,len-1).toString();
}
}
}
測試程式碼:
package LinkListStack;
/**
* Created by jiangxs on 17-5-24.
*/
public class LinkListStackTest {
public static void main(String[] args) {
LinkListStack<String> ll = new LinkListStack<String>();
System.out.println("原棧中的元素: "+ll);
System.out.println("----------進棧啦----------");
//壓棧
ll.push("haha");
ll.push("hehe");
ll.push("xixi");
ll.push("hiahia");
ll.push("heihei");
System.out.println("壓棧後棧中所含元素: "+ll);
//獲取棧頂元素
System.out.println("棧頂元素為: "+ll.getTop());
//獲取棧中元素個數
System.out.println("當前棧中元素個數為: "+ll.getSize());
//出棧
System.out.println("----------出棧啦----------");
ll.pop();
System.out.println("出棧後棧中所含元素: "+ll);
//獲取棧頂元素
System.out.println("棧頂元素為: "+ll.getTop());
//獲取棧中元素個數
System.out.println("當前棧中元素個數為: "+ll.getSize());
}
}
測試結果:
原棧中的元素: []
----------進棧啦----------
壓棧後棧中所含元素: [heihei->hiahia->xixi->hehe->haha]
棧頂元素為: heihei
當前棧中元素個數為: 5
----------出棧啦----------
出棧後棧中所含元素: [hiahia->xixi->hehe->haha]
棧頂元素為: hiahia
當前棧中元素個數為: 4
Process finished with exit code 0
轉載:https://blog.csdn.net/u013393958/article/details/72675276