日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java中堆栈的基本操作_玩儿转队列和栈的基本操作及其应用:Java 版

發布時間:2024/9/27 java 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java中堆栈的基本操作_玩儿转队列和栈的基本操作及其应用:Java 版 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

隊列的基本操作

隊列入隊出隊實現

隊列是種先進先出的數據結構。

隊列的基本操作主要是入隊和出隊。

數據從隊尾進入隊列,從隊首出隊列。

下面來寫一個簡單的隊列:

public class MyQueue {

private List data;

private int pointer;

public MyQueue() {

data = new ArrayList<>();

pointer = 0;

}

public boolean isEmpty() {

return pointer >= data.size();

}

/**

* Get the front item from the queue.

*/

public int Front() {

return data.get(pointer);

}

/**

* Insert an element into the queue. Return true if the operation is successful.

*/

public boolean enQueue(int x) {

data.add(x);

return true;

}

/**

* Delete an element from the queue. Return true if the operation is successful.

*/

public boolean deQueue() {

if (isEmpty()) {

return false;

}

pointer++;

return true;

}

}

其中,pointer代表頭隊首第一個位置的數據。

當頭部有數據出隊時,對應的pointer指針會往后移動一位。

如果有數據入隊,會直接加在隊尾:

我們會發現,隨著隊首數據的數據的出隊,隊首指針之前的空間都會被浪費掉,而且隨著使用次數變多,空間浪費會越來越高。

為了重復使用這部分空間,避免浪費,我們可以設計一個隊首與隊尾相連接的隊列,重復利用空間。

循環隊列設計

如上圖所示,數據1 ~ 10依次入隊,隊首head在1處,隊尾tail在10處,如果將1出隊列,head頭指針將移動到2:

此時,有一個空位,我們還可以繼續入隊:

這樣利用空間,剛好可以把隊首浪費的空間利用上。

class MyCircularQueue {

private Integer[] data; //隊列數據

private Integer size; //隊列大小

private Integer head = -1; //頭指針

private Integer tail = -1; //尾指針

/**

* 初始化隊列

*/

public MyCircularQueue(int k) {

this.data = new Integer[k];

this.size = k;

}

/**

* 入隊操作

*/

public boolean enQueue(int value) {

if (isFull()) {

return false;

}

if (head == -1) {

head++;

}

tail++;

data[tail % size] = value;

return true;

}

/**

* 出隊操作

*/

public boolean deQueue() {

if (isEmpty()) {

return false;

}

if (head == tail % size) {

head = -1;

tail = -1;

} else {

head++;

}

return true;

}

/**

* 獲取隊首元素

*/

public int Front() {

if (isEmpty()) {

return -1;

}

return data[head];

}

/**

* 獲取隊尾元素

*/

public int Rear() {

if (isEmpty()) {

return -1;

}

return data[tail % size];

}

/**

* 判斷隊列是不是為空

*/

public boolean isEmpty() {

return tail == -1 && head == -1;

}

/**

* 檢查隊列是不是已經滿了

*/

public boolean isFull() {

return (tail % size - head) == size - 1 || (head - tail % size) == 1;

}

}

廣度優先搜索(BFS)及其實現

上面我們已經實現過基本的隊列已經如果優化隊列,下面我們來看一個隊列在 BFS(廣度優先搜索)算法中的應用。

首先我們來定義結點:

@Getter

@Setter

@EqualsAndHashCode

@NoArgsConstructor

class Node implements Serializable {

private static final long serialVersionUID = 3687337665231315466L;

String value;

Collection previews; //前置結點

Collection tails; //后置結點

public Node(String value, Collection previews, Collection tails) {

this.value = value;

}

public Node(String value) {

this.value = value;

}

}

之后,我們先用隊列來實現簡單的BFS:

int BFS(Node root, Node target) {

Queue queue = new LinkedBlockingQueue(); // store all nodes which are waiting to be processed

int step = 0; // number of steps neeeded from root to current node

queue.add(root);

while (!queue.isEmpty()) {

step++;

int size = queue.size();

for (int i = 0; i < size; i++) {

Node cur = queue.poll();

if (cur.equals(target)) {

return step;

}

if (cur.tails != null) {

for (Node node : cur.tails) {

queue.add(node);

}

}

}

}

return -1;

}

另外,考慮到圖結構中,像上面這樣訪問,可能會存在訪問重復結點的情況,所以,我們記錄下訪問過的結點,訪問過就直接跳過。

下面是改進算法:

/**

* 避免一個節點訪問兩次,單獨檢查訪問過的結點

*

* @param root

* @param target

* @return

*/

int BFS(Node root, Node target) {

Queue queue = new LinkedBlockingQueue(); // store all nodes which are waiting to be processed

Set userd = new HashSet<>(); // node that be used

int step = 0; // number of steps neeeded from root to current node

queue.add(root);

userd.add(root);

while (!queue.isEmpty()) {

step++;

int size = queue.size();

for (int i = 0; i < size; i++) {

Node cur = queue.poll();

if (cur.equals(target)) {

return step;

}

if (cur.tails != null) {

for (Node node : cur.tails) {

if (!userd.contains(node)) {

queue.add(node);

userd.add(node);

}

}

}

}

}

return -1;

}

Stack

與隊列相反,棧是種先入后出的結構。

下面我們來看下Java里面的棧基本入棧和出棧是如何實現的:

首先是入棧操作:

/**

* Pushes an item onto the top of this stack. This has exactly

* the same effect as:

*

* addElement(item)

*

* @param item the item to be pushed onto this stack.

* @return the item argument.

* @see java.util.Vector#addElement

*/

public E push(E item) {

addElement(item);

return item;

}

/**

* Adds the specified component to the end of this vector,

* increasing its size by one. The capacity of this vector is

* increased if its size becomes greater than its capacity.

*

*

This method is identical in functionality to the

* {@link #add(Object) add(E)}

* method (which is part of the {@link List} interface).

*

* @param obj the component to be added

*/

public synchronized void addElement(E obj) {

modCount++;

ensureCapacityHelper(elementCount + 1);

elementData[elementCount++] = obj;

}

入棧 操作即將數據插入數組尾部。ps:入棧之前會去進行容量檢查,如果不夠,會進行內部數組的擴容操作,會重新產生大容量數組,并將原來老數組拷貝到新數組,完成擴容。過程跟 ArrayList 的類似。

下面來看下出棧:

/**

* Removes the object at the top of this stack and returns that

* object as the value of this function.

*

* @return The object at the top of this stack (the last item

* of the Vector object).

* @throws EmptyStackException if this stack is empty.

*/

public synchronized E pop() {

E obj;

int len = size();

obj = peek();

removeElementAt(len - 1);

return obj;

}

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--;

elementData[elementCount] = null; /* to let gc do its work */

}

這里,直接將數組尾部的數移除。

深度優先搜索(DFS)

首先來看DFS的簡單遞歸實現:

/*

* 基于遞歸實現 DFS

*/

boolean DFS(Node cur, Node target, Set visited) {

if (cur == target) {

return true;

}

if (cur.tails == null || cur.tails.size() < 1) {

return false;

}

for (Node n : cur.tails) {

visited.add(n);

if (DFS(n, target, visited)) {

return true;

}

}

return false;

}

基于遞歸的實現,系統會自動幫我們生成堆棧調用,但是如果遞歸的深度過高的話,終將造成堆棧溢出。這時候,我們就需要自己用Stack實現這一過程:

/**

* 基于 stack

*

* @param cur

* @param target

* @return

*/

boolean DFS(Node cur, Node target) {

Set visited = new HashSet<>();

Stack stack = new Stack();

stack.push(cur);

while (!stack.isEmpty()) {

Node temp = stack.pop();

if (temp == target) {

return true;

}

for (Node n : temp.tails) {

if (!visited.contains(n)) {

visited.add(n);

stack.push(n);

}

}

}

return false;

}

總結

以上是生活随笔為你收集整理的java中堆栈的基本操作_玩儿转队列和栈的基本操作及其应用:Java 版的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。