最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java數(shù)據(jù)結(jié)構(gòu)之隊(duì)列與OJ題

 更新時(shí)間:2023年01月07日 17:34:38   作者:程序猿教你打籃球  
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)之隊(duì)列與OJ題,本文章先是對(duì)隊(duì)列進(jìn)行介紹,后又介紹了四道OJ相關(guān)的題目,來(lái)使其深入理解,需要的朋友可以參考下

什么是隊(duì)列? 

隊(duì)列:只允許在一端進(jìn)行插入數(shù)據(jù)操作,在另一端進(jìn)行刪除數(shù)據(jù)操作的特殊線性表,隊(duì)列具有先進(jìn)先出FIFO(First In First Out)

入隊(duì)列:進(jìn)行插入操作的一端稱為隊(duì)尾!

出隊(duì)列:進(jìn)行刪除操作的一 端稱為隊(duì)頭!

隊(duì)列也可以數(shù)組和鏈表的結(jié)構(gòu)實(shí)現(xiàn),使用鏈表的結(jié)構(gòu)實(shí)現(xiàn)更優(yōu)一些,因?yàn)槿绻褂脭?shù)組的結(jié)構(gòu), 出隊(duì)列在數(shù)組頭上出數(shù)據(jù),效率會(huì)比較低。

初識(shí)Queue

認(rèn)識(shí)一下Queue

如圖可見,Queue本質(zhì)上是一個(gè)接口,被Deque(雙端隊(duì)列)繼承,被LinkedList實(shí)現(xiàn),所以Queue底層是通過鏈表來(lái)實(shí)現(xiàn)的,而Queue是不能實(shí)例化對(duì)象的, 所以我們想使用隊(duì)列,則需要new一個(gè)LinkedeList對(duì)象,實(shí)現(xiàn)向上轉(zhuǎn)型,這樣就可以使用Queue中的方法了:

add 和 offer 都是入隊(duì)列,這兩個(gè)區(qū)別是當(dāng)使用add時(shí),一些隊(duì)列有大小限制,如果想在一個(gè)滿的隊(duì)列中加入新的元素時(shí),調(diào)用 add() 方法就會(huì)拋出一個(gè) unchecked 異常,而調(diào)用 offer() 方法會(huì)返回 false。因此就可以在程序中進(jìn)行有效的判斷!

簡(jiǎn)單使用下Queue

public static void main(String[] args) {
    Queue<Integer> queue = new LinkedList<>();
    queue.offer(1);
    queue.offer(2);
    queue.offer(3);
    System.out.println(queue.peek()); //獲取對(duì)頭元素 -> 1
    System.out.println(queue.poll()); //出隊(duì)頭元素 -> 1
    System.out.println(queue.peek()); //獲取對(duì)頭元素 -> 2
    System.out.println(queue.isEmpty()); //判斷隊(duì)列是否為null -> false
    queue.clear(); //清空隊(duì)列
    System.out.println(queue.isEmpty()); //判斷隊(duì)列是否為null -> true
}

模擬實(shí)現(xiàn)Queue 

構(gòu)造方法和成員屬性

public class MyQueue { 
    private class Node { 
        private int val; //數(shù)據(jù)域 
        private Node next; //指針域名 
        private Node(int val) { 
            this.val = val; 
         } 
    } 
    //隊(duì)頭入,隊(duì)尾出 
    private Node head; //隊(duì)頭引用 
    private Node last; //隊(duì)尾引用 
    private int size; //隊(duì)列有效數(shù)據(jù)個(gè)數(shù)
    }

offer 方法

// 隊(duì)尾入隊(duì)列
public boolean offer(int val) { 
    Node newNode = new Node(val); 
    // 如果是第一次入隊(duì)列 
    if (this.head == null) { 
        this.head = newNode; 
        this.last = newNode;
    } else { 
        this.last.next = newNode; 
        this.last = this.last.next; 
    } 
    this.size++; 
    return true;
}

poll 方法

// 隊(duì)頭出隊(duì)列
public int poll() { 
    Node node = this.head;
    // 如果隊(duì)列為null 
    if (this.head == null) { 
        throw new MyQueueIsEmptyException("隊(duì)列為空!"); 
    } else { 
        this.head = this.head.next; 
    } 
    this.size--; 
    return node.val;
}

peek 方法

// 取隊(duì)頭元素
public int peek() { 
    // 如果隊(duì)列為null 
    if (this.head == null) { 
        throw new MyQueueIsEmptyException("隊(duì)列為空!"); 
    } 
    else { 
        return this.head.val;
    }
}

至于size和empty方法,就交給各位小伙伴實(shí)現(xiàn)了,由于有了前面鏈表的基礎(chǔ),隊(duì)列實(shí)現(xiàn)起來(lái)是比較簡(jiǎn)單的,所以更多希望閱讀文章的初學(xué)者能下來(lái)多自己手寫以下,畫畫圖。

隊(duì)列相關(guān)的OJ題 

設(shè)計(jì)循環(huán)隊(duì)列 (來(lái)源:LeetCode 難度:中等)  

題目:設(shè)計(jì)你的循環(huán)隊(duì)列實(shí)現(xiàn)。 循環(huán)隊(duì)列是一種線性數(shù)據(jù)結(jié)構(gòu),其操作表現(xiàn)基于 FIFO(先進(jìn)先出)原則并且隊(duì)尾被連接在隊(duì)首之后以形成一個(gè)循環(huán)。它也被稱為“環(huán)形緩沖器”。

循環(huán)隊(duì)列的一個(gè)好處是我們可以利用這個(gè)隊(duì)列之前用過的空間。在一個(gè)普通隊(duì)列里,一旦一個(gè)隊(duì)列滿了,我們就不能插入下一個(gè)元素,即使在隊(duì)列前面仍有空間。但是使用循環(huán)隊(duì)列,我們能使用這些空間去存儲(chǔ)新的值。

你的實(shí)現(xiàn)應(yīng)該支持如下操作:

MyCircularQueue(k): 構(gòu)造器,設(shè)置隊(duì)列長(zhǎng)度為 k 。
Front: 從隊(duì)首獲取元素。如果隊(duì)列為空,返回 -1 。
Rear: 獲取隊(duì)尾元素。如果隊(duì)列為空,返回 -1 。
enQueue(value): 向循環(huán)隊(duì)列插入一個(gè)元素。如果成功插入則返回真。
deQueue(): 從循環(huán)隊(duì)列中刪除一個(gè)元素。如果成功刪除則返回真。
isEmpty(): 檢查循環(huán)隊(duì)列是否為空。
isFull(): 檢查循環(huán)隊(duì)列是否已滿。

解題思路:對(duì)于這道題來(lái)說(shuō),我們有很多種解題思路,但我們要注意一點(diǎn),如何區(qū)分隊(duì)列為空和隊(duì)列滿的情況?這里可以添加size屬性記錄,也可使用標(biāo)記,也可也空一個(gè)位置出來(lái)區(qū)分,那么今天我們就空一個(gè)位置,那么如何區(qū)分隊(duì)列空和隊(duì)列滿呢?見下圖:

對(duì)于循環(huán)隊(duì)列的實(shí)現(xiàn)我們采用的時(shí)數(shù)組方案,有front和rear分別存儲(chǔ)隊(duì)頭下標(biāo)和隊(duì)尾元素的后一個(gè)下標(biāo)。至于更多需要注意細(xì)節(jié)的地方,比如修正front和rear的位置時(shí),在代碼中有對(duì)應(yīng)的注釋,查看即可:

public class MyCircularQueue {
 
    private int array[]; //存放數(shù)據(jù)的數(shù)組
    private int front; // 隊(duì)頭下標(biāo)
    private int rear; // 隊(duì)尾下標(biāo)
 
    public MyCircularQueue(int k) {
        this.array = new int[k + 1]; //因?yàn)槲覀円速M(fèi)一個(gè)空間,所以需要多開辟一個(gè)空間
    }
 
    // 入隊(duì)列
    public boolean enQueue(int value) {
        // 如果隊(duì)列滿的情況
        if (isFull()) {
            return false;
        }
        // 沒有滿就往隊(duì)尾入元素
        this.array[this.rear] = value;
        // rear往前走一步,需要空出一個(gè)位置,所以當(dāng)rear走到length-1時(shí),需要修正下rear
        this.rear = (this.rear + 1) % this.array.length;
        return true;
    }
 
    // 出隊(duì)列
    public boolean deQueue() {
        // 如果隊(duì)列為null的情況
        if (isEmpty()) {
            return false;
        }
        // 從隊(duì)頭出隊(duì)列,需要修正隊(duì)頭的位置
        this.front = (this.front + 1) % this.array.length;
        return true;
    }
    
    // 取隊(duì)頭元素
    public int Front() {
        // 如果隊(duì)列為null的情況
        if (isEmpty()) {
            return -1;
        }
        return this.array[this.front]; //返回隊(duì)頭元素
    }
 
    // 取隊(duì)尾元素
    public int Rear() {
        // 如果隊(duì)列為null的情況
        if (isEmpty()) {
            return -1;
        }
        // 如果rear為0的情況,我們需要特殊處理
        int index = this.rear == 0 ? this.array.length - 1 : this.rear - 1;
        return this.array[index]; //返回隊(duì)尾元素
    }
 
    // 判斷隊(duì)列是否為空
    public boolean isEmpty() {
        // 當(dāng)front和rear相遇了,則表示隊(duì)列中沒有元素
        return this.front == this.rear;
    }
 
    // 判斷隊(duì)列是否滿了
    public boolean isFull() {
        // 因?yàn)槲覀儠?huì)浪費(fèi)一個(gè)空間,所以rear+1等于front就滿了
        // 但是我們要rear防止越界,所以要進(jìn)行修正:(this.rear + 1) % this.array.length
        return (this.rear + 1) % this.array.length == this.front;
    }
}

用隊(duì)列實(shí)現(xiàn)棧 (來(lái)源:LeetCode 難度:簡(jiǎn)單)

題目:請(qǐng)你僅使用兩個(gè)隊(duì)列實(shí)現(xiàn)一個(gè)后入先出(LIFO)的棧,并支持普通棧的全部四種操作(push、top、pop 和 empty)。

實(shí)現(xiàn) MyStack 類:

void push(int x) 將元素 x 壓入棧頂。
int pop() 移除并返回棧頂元素。
int top() 返回棧頂元素。
boolean empty() 如果棧是空的,返回 true ;否則,返回 false 。

解題思路:這道題的解題思路并不難,我們只需要定義兩個(gè)隊(duì)列,入棧的時(shí)候往不為null的隊(duì)列入,出棧的時(shí)候先將不為空的隊(duì)列的size()-1個(gè)元素全部放到為空的隊(duì)列中,剩余最后一個(gè)元素直接出棧即可,由于取棧頂元素不用刪除元素,所以剩余的最后一個(gè)元素還要放入另一個(gè)隊(duì)列中,至于更詳細(xì)的內(nèi)容可以配合下面代碼和注釋閱讀:

class MyStack {
    private Queue<Integer> qu1;
    private Queue<Integer> qu2;
 
    public MyStack() {
        this.qu1 = new LinkedList<>();
        this.qu2 = new LinkedList<>();
    }
    
    public void push(int x) {
        // 兩個(gè)隊(duì)列都為null的情況
        if (this.qu1.isEmpty() && this.qu2.isEmpty()) {
            this.qu1.offer(x);
            return;
        }
 
        // 哪個(gè)隊(duì)列不為null往哪個(gè)隊(duì)列中入元素
        if (!this.qu1.isEmpty()) {
            this.qu1.offer(x);
        } else {
            this.qu2.offer(x);
        }
    }
    
    public int pop() {
        // 如果兩個(gè)隊(duì)列都為空的情況下,就不能出隊(duì)操作
        if (empty()) {
            return -1;
        }
        // 先將不為空的隊(duì)列的size-1個(gè)元素全部放到為空的隊(duì)列中
        if (!this.qu1.isEmpty()) {
            while (qu1.size() - 1 != 0) {
                qu2.offer(qu1.poll());
            }
            return qu1.poll(); //返回最后一個(gè)元素
        } else {
            while (qu2.size() - 1 != 0) {
                qu1.offer(qu2.poll());
            }
            return qu2.poll(); //返回最后一個(gè)元素
        }
    }
    
    public int top() {
        // 如果隊(duì)列為null
        if (empty()) {
            return -1;
        }
        int ret = 0; //保留剩余最后一個(gè)棧頂元素的變量
        // 先將不為空的隊(duì)列的size-1個(gè)元素全部放到為空的隊(duì)列中
        if (!this.qu1.isEmpty()) {
            while (qu1.size() - 1 != 0) {
                qu2.offer(qu1.poll());
            }
            ret = qu1.peek();
            qu2.offer(qu1.poll());
        } else {
            while (qu2.size() - 1 != 0) {
                qu1.offer(qu2.poll());
            }
            ret = qu2.peek();
            qu1.offer(qu2.poll()); //取棧頂元素不能刪除掉,還得入另一個(gè)隊(duì)列中去
        }
        return ret;
    }
    
    public boolean empty() {
        return this.qu1.isEmpty() && this.qu2.isEmpty(); //兩個(gè)隊(duì)列都為空,棧才為空
    }
}

用棧實(shí)現(xiàn)隊(duì)列 (來(lái)源:LeetCode 難度:簡(jiǎn)單)

題目:請(qǐng)你僅使用兩個(gè)棧實(shí)現(xiàn)先入先出隊(duì)列。隊(duì)列應(yīng)當(dāng)支持一般隊(duì)列支持的所有操作(push、pop、peek、empty)。

實(shí)現(xiàn) MyQueue 類:

void push(int x) 將元素 x 推到隊(duì)列的末尾
int pop() 從隊(duì)列的開頭移除并返回元素
int peek() 返回隊(duì)列開頭的元素
boolean empty() 如果隊(duì)列為空,返回 true ;否則,返回 false

解題思路:這道題我們可以這樣做,定義兩個(gè)棧,分別是pushStack和popStack,入隊(duì)統(tǒng)一都入到pushStack棧中,出隊(duì)頭元素都從popStack中出,如果popStack是空的情況,就先將pushStack棧中所有的元素放入popStack中,再出棧頂元素。 至于判斷隊(duì)列是否為空,需要滿足 pushStack和popStack都為空,隊(duì)列才為空!

class MyQueue {
    private Stack<Integer> pushStack;
    private Stack<Integer> popStack;
    public MyQueue() {
        this.pushStack = new Stack<>();
        this.popStack = new Stack<>();
    }
    
    public void push(int x) {
        // 入隊(duì)列都在pushStack中
        this.pushStack.push(x);
    }
    
    public int pop() {
        // 出隊(duì)列都從popStack出
        if (popStack.empty()) {
            // 把pushStack棧中的元素都放到popStack棧中
            while (!pushStack.empty()) {
                popStack.push(pushStack.pop());
            }
        }
        if (!popStack.empty()) {
            return popStack.pop();
        } else {
            return -1;
        }
    }
    
    public int peek() {
        // 取隊(duì)頭元素都從popStack中取
        if (popStack.empty()) {
            // 把pushStack棧中的元素都放到popStack棧中
            while (!pushStack.empty()) {
                popStack.push(pushStack.pop());
            }
        }
        if (!popStack.empty()) {
            return popStack.peek();
        } else {
            return -1;
        }
    }
    
    public boolean empty() {
        return pushStack.empty() && popStack.empty();
    }
}

最小棧 (來(lái)源:LeetCode 難度:中等)

題目:設(shè)計(jì)一個(gè)支持 push ,pop ,top 操作,并能在常數(shù)時(shí)間內(nèi)檢索到最小元素的棧。

實(shí)現(xiàn) MinStack 類:

MinStack() 初始化堆棧對(duì)象。
void push(int val) 將元素val推入堆棧。
void pop() 刪除堆棧頂部的元素。
int top() 獲取堆棧頂部的元素。
int getMin() 獲取堆棧中的最小元素。

解題思路:這道題一看就需要用到兩個(gè)棧,一個(gè)棧入數(shù)據(jù),一個(gè)棧始終壓入最小值,如何操作呢?這里我們可以定義兩個(gè)棧,分別是stack和minStack,入棧的時(shí)候入stack這個(gè)棧,如果是第一次入棧,則當(dāng)前入棧元素為最小值,同時(shí)也需要入minStack棧中,如果后續(xù)入棧元素小于或等于minStack棧頂元素,則也需要入minStack棧,如果比minStack棧頂元素大,則不需要入minStack棧了,出棧的時(shí)候,判斷stack棧如果與minStack棧元素相等,則minStack也要出棧頂元素!

public class MinStack {
    private Stack<Integer> stack;
    private Stack<Integer> minStack;
    public MinStack() {
        this.stack = new Stack<>();
        this.minStack = new Stack<>();
    }
    
    public void push(int val) {
        // 如果stack為null,表示第一次入棧,
        // 此時(shí)入棧的元素也是此時(shí)棧中最小值,也要入minStack棧
        if (this.stack.isEmpty()) {
            this.stack.push(val);
            this.minStack.push(val);
            return;
        }
        this.stack.push(val);
        // 如果stack棧頂元素小于等于minStack棧頂元素,則也需要入minStack棧中
        if (this.stack.peek() <= this.minStack.peek()) {
            this.minStack.push(val);
        }
    }
 
    // 出棧
    public void pop() {
        if (this.stack.isEmpty()) {
            return;
        }
        // 如果出棧元素與minStack元素相等,minStack也要出棧
        if (this.stack.pop().equals(this.minStack.peek())) {
            this.minStack.pop();
        }
    }
 
    // 取棧頂元素
    public int top() {
        if (this.stack.isEmpty()) {
            return -1;
        } else {
            return this.stack.peek();
        }
    }
 
    // 取棧中最小元素
    public int getMin() {
        if (this.stack.isEmpty()) {
            return -1;
        } else {
            return this.minStack.peek();
        }
    }
}

到此這篇關(guān)于Java 數(shù)據(jù)結(jié)構(gòu)之隊(duì)列與OJ題的文章就介紹到這了,更多相關(guān)Java數(shù)據(jù)結(jié)構(gòu) 隊(duì)列與OJ題內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java課設(shè)案例之百行代碼實(shí)現(xiàn)簡(jiǎn)易計(jì)算器

    Java課設(shè)案例之百行代碼實(shí)現(xiàn)簡(jiǎn)易計(jì)算器

    下面這篇文章主要給大家介紹了關(guān)于Java課設(shè)案例之百行代碼實(shí)現(xiàn)簡(jiǎn)易計(jì)算器的相關(guān)資料,這是一個(gè)關(guān)于java簡(jiǎn)單計(jì)算器的完整課程設(shè)計(jì)以及源碼,需要的朋友可以參考下
    2023-06-06
  • 6種SpringBoot中自定義starter的方式介紹

    6種SpringBoot中自定義starter的方式介紹

    在SpringBoot生態(tài)中,starter是一種特殊的依賴,它能夠自動(dòng)裝配相關(guān)組件,簡(jiǎn)化項(xiàng)目配置,本文將詳細(xì)介紹6種不同的自定義starter開發(fā)方法,有需要的可以了解下
    2025-04-04
  • Java實(shí)現(xiàn)Dijkstra算法的示例代碼

    Java實(shí)現(xiàn)Dijkstra算法的示例代碼

    Dijkstra(迪杰斯特拉)算法是典型的單源最短路徑算法,用于計(jì)算一個(gè)節(jié)點(diǎn)到其他所有節(jié)點(diǎn)的最短路徑。本文主要介紹了實(shí)現(xiàn)這一算法的Java代碼,需要的可以參考一下
    2022-07-07
  • Java面向?qū)ο笾饔糜蛟敿?xì)解讀

    Java面向?qū)ο笾饔糜蛟敿?xì)解讀

    這篇文章主要介紹了Java面向?qū)ο笾饔糜蛟敿?xì)解讀,在java編程中,主要的變量就是屬性和局部變量,局部變量一般是指在成員方法中定義的變量,局部變量也就是除了屬性之外的其他變量,作用域?yàn)槎x他的代碼塊中,需要的朋友可以參考下
    2024-01-01
  • JavaWeb Spring依賴注入深入學(xué)習(xí)

    JavaWeb Spring依賴注入深入學(xué)習(xí)

    這篇文章主要為大家詳細(xì)介紹了JavaWeb Spring依賴注入,深入學(xué)習(xí)Spring依賴注入,感興趣的小伙伴們可以參考一下
    2016-09-09
  • java并發(fā)包中CountDownLatch和線程池的使用詳解

    java并發(fā)包中CountDownLatch和線程池的使用詳解

    這篇文章主要介紹了java并發(fā)包中CountDownLatch和線程池的使用詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧
    2021-02-02
  • win10操作系統(tǒng)下重啟電腦java環(huán)境變量失效

    win10操作系統(tǒng)下重啟電腦java環(huán)境變量失效

    這篇文章主要介紹了win10操作系統(tǒng)下重啟電腦java環(huán)境變量失效,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • SpringBoot整合Spring Security構(gòu)建安全的Web應(yīng)用

    SpringBoot整合Spring Security構(gòu)建安全的Web應(yīng)用

    pring Security是一個(gè)強(qiáng)大的身份驗(yàn)證和訪問控制框架,本文主要介紹了SpringBoot整合Spring Security構(gòu)建安全的Web應(yīng)用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • Java中的cglib原理解析

    Java中的cglib原理解析

    這篇文章主要介紹了Java中的cglib原理解析,由于代理類繼承了被代理類,所以調(diào)用sayHello()方法時(shí)會(huì)直接調(diào)用代理類的sayHello()方法,而在代理類的方法中,調(diào)用了Callback的邏輯,需要的朋友可以參考下
    2023-10-10
  • 淺談JDK8中的Duration Period和ChronoUnit

    淺談JDK8中的Duration Period和ChronoUnit

    在JDK8中,引入了三個(gè)非常有用的時(shí)間相關(guān)的API:Duration,Period和ChronoUnit。他們都是用來(lái)對(duì)時(shí)間進(jìn)行統(tǒng)計(jì)的,本文將會(huì)詳細(xì)講解一下這三個(gè)API的使用
    2021-06-06

最新評(píng)論

衡水市| 新民市| 荔波县| 东乌珠穆沁旗| 城固县| 建湖县| 黎川县| 新民市| 综艺| 收藏| 沿河| 景谷| 江口县| 江孜县| 霍城县| 禄丰县| 德州市| 九江市| 西乌珠穆沁旗| 连云港市| 驻马店市| 灵石县| 孝义市| 金秀| 阳新县| 肃南| 抚州市| 遂昌县| 定西市| 禹城市| 马公市| 临沭县| 巧家县| 民权县| 留坝县| 灵川县| 双江| 龙泉市| 瓮安县| 达尔| 句容市|