數據結構與算法 - 棧和隊列


棧(stack)

先進后出,刪除與加入均在棧頂操作

 

棧也稱為堆棧,是一種線性表。

堆棧的特性: 最先放入堆棧中的內容最后被拿出來,最后放入堆棧中的內容最先被拿出來, 被稱為先進后出、后進先出。

堆棧中兩個最重要的操作是PUSH和POP,兩個是相反的操作。

PUSH:在堆棧的頂部加入一 個元素。

POP:在堆棧頂部移去一個元素, 並將堆棧的大小減一。

 

  在成員變量方面,Vector提供了elementData , elementCount, capacityIncrement三個成員變量。其中

         elementData :"Object[]類型的數組",它保存了Vector中的元素,可以隨着元素的增加而動態的增長,如果在初始化Vector時沒有指定容器大小,則使用默認大小為10.

 private static final int DEFAULT_SIZE = 10;初始化的值

 protected int elementCount; 棧元素數量(非空元素的長度)

 

/** * 使用指定的初始容量和容量增量構造一個空的向量。 */
 
public Vector(int initialCapacity, int capacityIncrement) { //初始化
      super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity); this.elementData = new Object[initialCapacity]; this.capacityIncrement = capacityIncrement; }

 

 protected int capacityIncrement;擴容增長因子向量的大小大於其容量時,容量自動增加的量。

如果在創建Vector時,指定了capacityIncrement的大小;則,每次當Vector中動態數組容量增加時>,增加的大小都是capacityIncrement。

如果容量的增量小於等於零,則每次需要增大容量時,向量的容量將增大一倍。

 

容量是最多能夠容納多少元素,而大小是目前容納了多少元素

 

得到最后元素的下標

public synchronized E peek(){   try{     return(E)elementData[elementCount-1];  //當前數組[當前數組長度-1] >>得到最后元素的下標
  }catch(IndexoutOfBoundsException e){          throw new EmptyStackException(); //得到下標,肯定會拋出異常
}}

 

出棧

@Suppres swarnings("unchecked") public synchronized E pop(){   if(slementCount==0){ //棧元素數量為0,表示空棧     throw new EmptyStackException(); //空棧異常
}
  final int index = --elementCount; //將來要出棧的非空元素下標,棧數量-1就是下標
                                 棧數量:1 2 3 4
                                  下標:0 1 2 3
  final E obj=(E)elementData[index]; //拿到棧頂元素,讓它等於obj
   elementData[index]=nul1;把棧頂變成null,下次再出棧,非空元素長度減一得到下標,又是有數據的了
  modCount++; //發生改變,進行加一操作
  return obj;
}

 

入棧

public synchronized void addElement(E object){   if(elementCount==elementData.1ength){//判斷是否棧滿     growByOne(); //棧滿,擴容一次,長度不定   } 
  elementData[ elementCount
++]=object;
  modCount++;
}

 

private void growByOne(){   int adding=0; //要添加的數量
  if(capacityIncrelent <=0){     if((adding=elementData.length)==0){ //如果是空棧,要添加元素的話,讓adding=1,增加一個元素 存疑?        adding=1;   } else{      adding = capacityIncrement; //capacityIncrement用它來判斷需要擴容多少
  }
E[] newData=newElementArray(elementData. length +adding);//新創建一個數組,把它的長度擴容成 增加的長度+擴容的
  System. arraycopy(elementData,0, newData,0, elementCount);//拷貝數據
  elementData=newData;
}

 

為什么每個方法里都要有全局變量和局部變量

安全問題:因為elementData可以會進行入棧和出棧操作,如果直接使用elementData,不能進行邊遍歷邊刪除,所以要使用局部變量Object[] dumpArray

棧里面可以有重復的元素

棧的遍歷可以從棧頂也可以從棧底,這個需要根據自己需求,為自己服務

 

棧的經典應用

 

 

 后綴表達式

931  -  3  *  +  10  2  /  +

923  *  +  10  2  /  +

96  +  10  2  /  +

15  10  2  /  +

15  5  +

20

 

中綴表達式 轉 后綴表達式: 數字輸出,運算符進棧,括號匹配出棧,棧頂優先級低出棧(精髓就是優先級越高越靠前)

9  + (3 - 1) ×  3  +  10  ÷  2       >>      931  -  3  *  +  10  2  /  +

            

           

 

 

 

 隊列

相對於棧而言,隊列的特性是:先進先出

  • 先排隊的小朋友肯定能先打到飯!

 

隊列的順序存儲

 

 缺點:出隊復雜度高0(n)

   容易假溢出

   容易造成資源浪費

隊列的鏈式存儲及結構模式

隊列的鏈式存儲結構,其實就是線性表的單鏈表,只不過它只能尾進頭出而已

 

 出隊:只需要讓頭指針指向a2,a1就出隊了

 入隊:只需要讓尾指針指向新結點,讓an的next結點指向新進來的結點

 

隊列也分成兩種:

  • 靜態隊列(數組實現)

  • 動態隊列(鏈表實現)

值得注意的是:往往實現靜態隊列,我們都是做成循環隊列

 

做成循環隊列的好處是不浪費內存資源

 

類到底采用什么樣的數據結構

 transient Link<E>voidLink;頭指針

 

public Linkedlist(){初始化 voidLink=new Link<E>(null, null, null); 創建
voidLink. previous = voidLink;
voidLink. next = voidLink; //前后指針都指向自己(自己抱着自己),后面進來的數據到底采用什么樣的數據結構要看add方法

 

 

 隊列隨機位置插入

public void add (int location, E object){ 二分法查找 link就是准備在這個位置插入一個新結點進來,當前結點 Link<E> previous = link.previous; Link<E> newLink = new Link<E>(object,previous(previous),link(next));//新結點 previous.next = newLink; link.previous = newLink; }

 


 

入隊(只有隊頭的情況下)

private boolean addlastImpl(E object){   Link<E>oldLast=voidLink. previous; //在沒有任何元素的情況下,void.link.previous等於它自己,也就是oldLast為head
  Link<E> newlink =new Link<E>(object, oldLast(previous指向head), voidlink(next也指向head));
  voidLink. previous =newlink;
  oldLast.next=newlink;
  size++;
  modCount++;
  return true;
}

 

本身就是一個循環,頭尾可以選擇,然后按照自己的選擇寫數據結構

 


 

 

出隊

voidlink = head

first = 0

next = 1

privateE removeFirstImpl(){ 
  Link<E>first = voidLink. next; //頭指針指向了第一個元素=first
  if(first = voidlink){ //如果first不等於voidlink,說明是有元素的     Link<E>next = first.next; //讓1=next,然后first.next指向它
   voidLink.next = next;
    next. previous = voidLink;
    size--;
    modCount++;
    return first.data;
  }
  throw new NoSuchElementException();
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM