中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

做網(wǎng)站掙錢么網(wǎng)站推廣是做什么的

做網(wǎng)站掙錢么,網(wǎng)站推廣是做什么的,網(wǎng)站設(shè)計(jì)滾動(dòng)圖片怎么做,市場(chǎng)調(diào)研公司成功案例文章目錄 棧和隊(duì)列?;靖拍顥5哪M實(shí)現(xiàn)集合框架中的棧棧的創(chuàng)建棧的方法棧的遍歷 棧的應(yīng)用及相關(guān)練習(xí)括號(hào)匹配逆波蘭表達(dá)式求值出棧入棧次序匹配最小棧 幾個(gè)含"棧"概念的區(qū)分 隊(duì)列基本概念隊(duì)列的模擬實(shí)現(xiàn)循環(huán)隊(duì)列雙端隊(duì)列集合框架中的隊(duì)列隊(duì)列的創(chuàng)建隊(duì)列的方法隊(duì)列…

文章目錄

  • 棧和隊(duì)列
      • 基本概念
      • 棧的模擬實(shí)現(xiàn)
      • 集合框架中的棧
        • 棧的創(chuàng)建
        • 棧的方法
        • 棧的遍歷
      • 棧的應(yīng)用及相關(guān)練習(xí)
        • 括號(hào)匹配
        • 逆波蘭表達(dá)式求值
        • 出棧入棧次序匹配
        • 最小棧
      • 幾個(gè)含"棧"概念的區(qū)分
    • 隊(duì)列
      • 基本概念
      • 隊(duì)列的模擬實(shí)現(xiàn)
      • 循環(huán)隊(duì)列
      • 雙端隊(duì)列
      • 集合框架中的隊(duì)列
        • 隊(duì)列的創(chuàng)建
        • 隊(duì)列的方法
        • 隊(duì)列的遍歷
      • 隊(duì)列的應(yīng)用及相關(guān)練習(xí)
        • 用隊(duì)列實(shí)現(xiàn)棧
        • 用棧實(shí)現(xiàn)隊(duì)列

棧和隊(duì)列

基本概念

是一種特殊的線性表,其只允許在固定的一端進(jìn)行插入和刪除元素操作,即 先進(jìn)后出

棧頂,即進(jìn)行數(shù)據(jù)插入和刪除操作的一端;棧底,即與棧頂相對(duì)的另一端。

棧的插入操作叫做壓棧/進(jìn)棧/入棧;棧的刪除操作叫做出棧/退棧/彈出。棧的插入和刪除操作都在棧頂一端。

【數(shù)據(jù)結(jié)構(gòu)入門】棧(Stack)的實(shí)現(xiàn)(定義、銷毀、入棧、出棧等) | 圖解數(shù)據(jù)結(jié)構(gòu),超詳細(xì)哦~_銷毀棧-CSDN博客


了解了基本的概念后,我們嘗試做一道小題,體會(huì)棧的先進(jìn)后出的特性:

進(jìn)棧序列為1,2,3,4 ,并且進(jìn)棧的過程中可以出棧,則不可能的出棧序列是()

A. 1,4,3,2 B. 2,3,4,1 C. 3,1,4,2 D. 3,4,2,1

想象現(xiàn)在有一個(gè)棧,最好還是畫圖,對(duì)于A:1進(jìn)1出2進(jìn)3進(jìn)4進(jìn)4出3出2出,滿足;對(duì)于B:1進(jìn)2進(jìn)2出3進(jìn)3出4進(jìn)4出1出,滿足;對(duì)于C:1進(jìn)2進(jìn)3進(jìn)3出,此時(shí)棧頂元素為2,只能先出2才能出1,所以該序列不可能為出棧序列,不滿足;對(duì)于D:1進(jìn)2進(jìn)3進(jìn)3出4進(jìn)4出2出1出,滿足

所以,答案為:C


棧的模擬實(shí)現(xiàn)

了解了棧以及棧的特性,思考,怎么實(shí)現(xiàn)一個(gè)棧,使其滿足棧的特性?

其實(shí),使用數(shù)組和鏈表都可以,我們需要實(shí)現(xiàn)的方法包括:

  • 入棧操作
  • 出棧操作
  • 獲取棧頂元素
  • 獲取棧中的有效元素個(gè)數(shù)
  • 判斷棧是否為空

接下來我們就分別使用數(shù)組和鏈表實(shí)現(xiàn)一個(gè)棧:

【數(shù)組實(shí)現(xiàn)?!?/strong>

實(shí)現(xiàn)一個(gè)類,類中定義一個(gè)數(shù)組成員變量,為了滿足棧的特性,數(shù)組只允許尾插和尾刪

大體框架如下:

public class MyStackByArray {public int[] elem;//棧public int capacity;//棧的容量public int usedSize;//棧的有效元素個(gè)數(shù)public MyStackByArray() {this.elem = new int[10];this.capacity = 10;}//入棧public void push(int data) {}//出棧并返回出棧元素public int pop() {}//獲取棧頂元素public int peek() {}//獲取棧中的有效元素public int size() {}//檢測(cè)棧是否為空public boolean empty() {}
}

public int size()

返回成員變量usedSize即可

    //獲取棧中的有效元素public int size() {return this.usedSize;}

public boolean empty()

    //檢測(cè)棧是否為空public boolean empty() {return this.usedSize == 0;}

public void push(int data)

由于數(shù)組下標(biāo)從0開始,所以成員變量usedSize其實(shí)就是下一次入棧的下標(biāo)位置。入棧前,我們要判斷棧是否滿,滿了要擴(kuò)容,之后進(jìn)行入棧即可:

    //入棧public void push(int data) {//棧滿則擴(kuò)容if(this.capacity == usedSize) {this.elem = Arrays.copyOf(elem, this.capacity * 2);this.capacity *= 2;}//入棧this.elem[this.usedSize] = data;this.usedSize++;}

public int pop()

出棧前,我們判斷棧是否為空,當(dāng)為空時(shí),我們選擇拋出一個(gè)自定義異常:StackIsException

public class StackIsEmptyException extends RuntimeException {public StackIsEmptyException(String message) {super(message);}
}

如果不為空,執(zhí)行出棧,注意,出棧直接讓usedSize--即可,不需要特意將棧頂元素置成0,因?yàn)楫?dāng)下次入棧時(shí)會(huì)覆蓋掉此元素

    //出棧并返回出棧元素public int pop() {//判斷棧是否為空if(empty()) {throw new StackIsEmptyException("The Stack Is Empty!: 棧為空!");}//出棧this.usedSize--;return this.elem[this.usedSize];}

public int peek()

獲取棧頂元素,判斷為空?為空拋出異常,否則返回

    //獲取棧頂元素public int peek() {//判斷棧是否為空if(empty()) {throw new StackIsEmptyException("The Stack Is Empty!: 棧為空!");}return this.elem[this.usedSize - 1];}

完整代碼:

public class MyStackByArray {public int[] elem;public int capacity;public int usedSize;public MyStackByArray() {this.elem = new int[10];this.capacity = 10;}//入棧public void push(int data) {//棧滿則擴(kuò)容if(this.capacity == usedSize) {this.elem = Arrays.copyOf(elem, this.capacity * 2);this.capacity *= 2;}//入棧this.elem[this.usedSize] = data;this.usedSize++;}//出棧并返回出棧元素public int pop() {//判斷棧是否為空if(empty()) {throw new StackIsEmptyException("The Stack Is Empty!: 棧為空!");}//出棧this.usedSize--;return this.elem[this.usedSize];}//獲取棧頂元素public int peek() {//判斷棧是否為空if(empty()) {throw new StackIsEmptyException("The Stack Is Empty!: 棧為空!");}return this.elem[this.usedSize - 1];}//獲取棧中的有效元素public int size() {return this.usedSize;}//檢測(cè)棧是否為空public boolean empty() {return this.usedSize == 0;}
}

【鏈表實(shí)現(xiàn)?!?/strong>

對(duì)于出棧,我們選擇頭刪,因?yàn)槲矂h得遍歷鏈表找到倒數(shù)第二個(gè)結(jié)點(diǎn),效率較低

對(duì)于入棧,我們選擇頭插,因?yàn)槌鰲_x擇的是頭刪,要滿足先進(jìn)后出,必須選擇頭插。

代碼比較簡(jiǎn)單,我們直接給出完整實(shí)現(xiàn):

public class MyStackByLinkedList {//鏈表結(jié)點(diǎn)類static class ListNode {public int val;public ListNode next;public ListNode(int val) {this.val = val;}}//鏈表第一個(gè)結(jié)點(diǎn)的引用public ListNode head;//入棧public void push(int data) {ListNode newNode = new ListNode(data);if(head == null) {head = newNode;return;}newNode.next = head;head = newNode;}//出棧并返回出棧元素public int pop() {if(empty()) {throw new StackIsEmptyException("The Stack Is Empty!: 棧為空!");}int ret = head.val;head = head.next;return ret;}//獲取棧頂元素public int peek() {if(empty()) {throw new StackIsEmptyException("The Stack Is Empty!: 棧為空!");}return head.val;}//獲取棧中的有效元素public int size() {int count = 0;ListNode cur = head;while(cur != null) {count++;cur = cur.next;}return count;}//檢測(cè)棧是否為空public boolean empty() {return head == null;}
}

集合框架中的棧

集合框架中,順序表對(duì)應(yīng)ArrayList,鏈表對(duì)應(yīng)LinkedList,那么棧對(duì)應(yīng)什么呢?

棧的創(chuàng)建

棧對(duì)應(yīng)三個(gè):Stack、LinkedListArrayDeque,即這三個(gè)類都可以作為棧

  • Stack類就是原生的棧類。只有無參構(gòu)造方法
  • LinkedList實(shí)現(xiàn)了Deque接口,Deque接口是雙端隊(duì)列接口,其中包含了操作棧的方法,所以LinkedList可作為鏈棧類。構(gòu)造方法有兩個(gè):無參構(gòu)造和利用其他容器的構(gòu)造
  • ArrayList也實(shí)現(xiàn)了Deque接口,實(shí)現(xiàn)了操作棧的方法,是基于數(shù)組的數(shù)據(jù)結(jié)構(gòu)。構(gòu)造方法有三個(gè):無參構(gòu)造、指定初始容量的構(gòu)造、利用其他容器的構(gòu)造
    在這里插入圖片描述
    public static void main(String[] args) {Stack<Integer> stack0 = new Stack<>();//StackLinkedList<Integer> stack1 = new LinkedList<>();//LinkedListArrayDeque<Integer> stack2 = new ArrayDeque<>();//ArrayDeque}

棧的方法
方法功能
E push(E e)將e入棧,并返回e
E pop()將棧頂元素出棧并返回
E peek()獲取棧頂元素
int size()獲取棧中的有效元素的個(gè)數(shù)
boolean empty()檢測(cè)棧是否為空
  • 注意:如果使用LinkedListArrayDeque實(shí)現(xiàn)棧,那么判空的方法為boolean isEmpty(),而不是boolean empty()
棧的遍歷

關(guān)于棧的遍歷,有三種方法,分別是迭代器、for-each和方法遍歷:

  • 對(duì)于StackLinkedListArrayDeque來說,利用方法遍歷的結(jié)果是一致的,都是按照"先進(jìn)后出’'的原則,并且這也是最常用的方法:
    public static void main(String[] args) {Stack<Integer> s1 = new Stack<>();LinkedList<Integer> s2 = new LinkedList<>();ArrayDeque<Integer> s3 = new ArrayDeque<>();s1.push(1);s1.push(2);s1.push(3);s2.push(1);s2.push(2);s2.push(3);s3.push(1);s3.push(2);s3.push(3);System.out.println("=====Stack=====");while(!s1.empty()) {System.out.print(s1.pop() + " ");}System.out.println();System.out.println("=====LinkedList=====");while(!s2.isEmpty()) {System.out.print(s2.pop() + " ");}System.out.println();System.out.println("=====ArrayDeque=====");while(!s3.isEmpty()) {System.out.print(s3.pop() + " ");}System.out.println();}

在這里插入圖片描述

  • Stack使用迭代器打印的順序是從棧底到棧頂,并不是出棧順序,這是因?yàn)?code>Stack是基于數(shù)組實(shí)現(xiàn)的,每次入棧都是在尾部;而LinkedListArrayDeque是按照出棧順序打印的,這是因?yàn)樗鼈內(nèi)霔6际窃陬^部/頂部進(jìn)行的(頭插)
    public static void main(String[] args) {Stack<Integer> s1 = new Stack<>();LinkedList<Integer> s2 = new LinkedList<>();ArrayDeque<Integer> s3 = new ArrayDeque<>();s1.push(1);s1.push(2);s1.push(3);s2.push(1);s2.push(2);s2.push(3);s3.push(1);s3.push(2);s3.push(3);System.out.println("=====Stack=====");Iterator<Integer> it1 = s1.iterator();while(it1.hasNext()) {System.out.print(it1.next() + " ");}System.out.println();System.out.println("=====LinkedList=====");Iterator<Integer> it2 = s2.iterator();while(it2.hasNext()) {System.out.print(it2.next() + " ");}System.out.println();System.out.println("=====ArrayDeque=====");Iterator<Integer> it3 = s3.iterator();while(it3.hasNext()) {System.out.print(it3.next() + " ");}System.out.println();}

在這里插入圖片描述

  • for-each遍歷的結(jié)果與迭代器遍歷的結(jié)果一致
    public static void main(String[] args) {Stack<Integer> s1 = new Stack<>();LinkedList<Integer> s2 = new LinkedList<>();ArrayDeque<Integer> s3 = new ArrayDeque<>();s1.push(1);s1.push(2);s1.push(3);s2.push(1);s2.push(2);s2.push(3);s3.push(1);s3.push(2);s3.push(3);System.out.println("=====Stack=====");for(Integer x : s1) {System.out.print(x + " ");}System.out.println();System.out.println("=====LinkedList=====");for(Integer x : s2) {System.out.print(x + " ");}System.out.println();System.out.println("=====ArrayDeque=====");for(Integer x : s3) {System.out.print(x + " ");}System.out.println();}

在這里插入圖片描述


棧的應(yīng)用及相關(guān)練習(xí)

棧的"先進(jìn)后出’'的特性,使得棧的應(yīng)用場(chǎng)景十分廣泛,比如,將序列逆序、遞歸轉(zhuǎn)化為非遞歸等等。

下面是幾道關(guān)于棧的經(jīng)典題目:

括號(hào)匹配

給定一個(gè)只包括 '('')''{''}''['']' 的字符串 s ,判斷字符串是否有效。

有效字符串需滿足:

  1. 左括號(hào)必須用相同類型的右括號(hào)閉合。
  2. 左括號(hào)必須以正確的順序閉合。
  3. 每個(gè)右括號(hào)都有一個(gè)對(duì)應(yīng)的相同類型的左括號(hào)。
class Solution {public boolean isValid(String s) {//補(bǔ)充代碼}
}

【思路】

遍歷字符串的每個(gè)字符,如果是左括號(hào)就入棧,如果是右括號(hào),就從棧中彈出一個(gè)元素,看左右括號(hào)是否匹配。

最終結(jié)果不匹配的原因可能是:

  • 只有左括號(hào) 或 只有右括號(hào) 或 左右括號(hào)數(shù)量不一致
  • 左右括號(hào)類型不匹配
class Solution {public boolean isValid(String s) {Stack<Character> stack = new Stack<>();int i = 0;for(i = 0; i < s.length(); i++) {char ch = s.charAt(i);if(ch == '(' || ch == '[' || ch == '{') {stack.push(ch);}else {if(stack.empty()) {return false;}else {char top = stack.pop();switch(top) {case '(':if(ch != ')') {return false;}break;case '[':if(ch != ']') {return false;}break;case '{':if(ch != '}') {return false;}break;}}}}if(!stack.empty()) {return false;}return true;}
}

原題鏈接:20. 有效的括號(hào) - 力扣(LeetCode)


逆波蘭表達(dá)式求值

給你一個(gè)字符串?dāng)?shù)組 tokens ,表示一個(gè)根據(jù) 逆波蘭表示法 表示的算術(shù)表達(dá)式。請(qǐng)你計(jì)算該表達(dá)式。返回一個(gè)表示表達(dá)式值的整數(shù)。

class Solution {public int evalRPN(String[] tokens) {//補(bǔ)充代碼}
}

【思路】

逆波蘭表達(dá)式,也叫后綴表達(dá)式,即將運(yùn)算符寫在操作數(shù)的后面。(我們平時(shí)習(xí)慣使用中綴表達(dá)式)舉個(gè)簡(jiǎn)單的例子:

對(duì)于中綴表達(dá)式:(1 + 2) * 3,轉(zhuǎn)化為后綴表達(dá)式:1 2 + 3 *

對(duì)于上面的后綴表達(dá)式的計(jì)算過程為: 尋找運(yùn)算符,即找到了+,然后將+前的兩個(gè)操作數(shù)執(zhí)行+運(yùn)算,得到3,此時(shí)表達(dá)式化簡(jiǎn)為3 3 *,繼續(xù)向后找到*運(yùn)算符,將前面兩個(gè)操作數(shù)執(zhí)行*運(yùn)算,得到9,此時(shí)9就是表達(dá)式的結(jié)果。

了解了后綴表達(dá)式的求解,我們就可以解決這道題目:

遍歷字符串?dāng)?shù)組,如果是數(shù)字就入棧,如果是運(yùn)算符就不入棧并從棧中彈出兩個(gè)元素,執(zhí)行運(yùn)算,將結(jié)果入棧,以此循環(huán),最終棧中會(huì)剩余一個(gè)元素,這個(gè)元素就是表達(dá)式的結(jié)果

注意的問題:

  • 題目給的是字符串?dāng)?shù)組,進(jìn)行運(yùn)算時(shí),要將字符串類型轉(zhuǎn)換為int類型
  • 彈出時(shí),先彈出的是右操作數(shù),后彈出的是左操作數(shù),注意兩者的順序,以免計(jì)算出錯(cuò)
class Solution {public int evalRPN(String[] tokens) {Stack<String> stack = new Stack<>();for(int i = 0; i < tokens.length; i++) {String s = tokens[i];if(s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/")) {int op2 = Integer.valueOf(stack.pop());int op1 = Integer.valueOf(stack.pop());switch(s) {case "+":stack.push(String.valueOf(op1 + op2));break;case "-":stack.push(String.valueOf(op1 - op2));break;case "*":stack.push(String.valueOf(op1 * op2));break;case "/":stack.push(String.valueOf(op1 / op2));break;} }else {stack.push(s);}}return Integer.valueOf(stack.pop());}
}

原題鏈接:150. 逆波蘭表達(dá)式求值 - 力扣(LeetCode)


出棧入棧次序匹配

輸入兩個(gè)整數(shù)序列,第一個(gè)序列表示棧的壓入順序,請(qǐng)判斷第二個(gè)序列是否可能為該棧的彈出順序。假設(shè)壓入棧的所有數(shù)字均不相等。例如序列1,2,3,4,5是某棧的壓入順序,序列4,5,3,2,1是該壓棧序列對(duì)應(yīng)的一個(gè)彈出序列,但4,3,5,1,2就不可能是該壓棧序列的彈出序列。

  1. 0<=pushV.length == popV.length <=1000
  2. -1000<=pushV[i]<=1000
  3. pushV 的所有數(shù)字均不相同
public class Solution {/*** 代碼中的類名、方法名、參數(shù)名已經(jīng)指定,請(qǐng)勿修改,直接返回方法規(guī)定的值即可** * @param pushV int整型一維數(shù)組 * @param popV int整型一維數(shù)組 * @return bool布爾型*/public boolean IsPopOrder (int[] pushV, int[] popV) {//補(bǔ)充代碼}
}

【思路】

遍歷入棧序列,每次將該次遍歷到的元素入棧,然后判斷當(dāng)前的棧頂元素是否與出棧序列的元素相等,即是否可以出棧,如果可以,就出棧(出棧一次后,遍歷出棧序列的指針也要后移),直到不能出棧了,繼續(xù)遍歷入棧序列,遍歷完成后,如果棧為空說明匹配。

    public boolean IsPopOrder (int[] pushV, int[] popV) {// write code hereStack<Integer> stack = new Stack<>();int j = 0;for(int i = 0; i < pushV.length; i++) {stack.push(pushV[i]);while(j < popV.length && !stack.isEmpty() && stack.peek() == popV[j]) {stack.pop();j++;}}return stack.isEmpty();}

注意:

  • while循環(huán)判斷是否可以出棧前,要判斷棧是否為空,否則可能會(huì)拋出??债惓?/mark>
  • j < popV.length在本題目中可以不寫,因?yàn)轭}目保證兩個(gè)序列長(zhǎng)度相等,如果測(cè)試用例給出的長(zhǎng)度不一定相等,那就需要加上

原題鏈接:棧的壓入、彈出序列_??皖}霸_??途W(wǎng) (nowcoder.com)


最小棧

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

class MinStack {public MinStack() {}public void push(int val) {}public void pop() {}public int top() {}public int getMin() {}
}

【思路】

維護(hù)兩個(gè)棧,一個(gè)是普通的棧,一個(gè)是存放最小值的棧,它的棧頂元素就是當(dāng)前狀態(tài)下的普通棧中的最小值,具體操作:

當(dāng)入棧時(shí),普通的棧直接入棧,如果最小值棧為空或者最小值棧的棧頂元素>=入棧元素,那么最小值棧也入棧該元素

當(dāng)出棧時(shí),普通的棧直接出棧,同時(shí)判斷普通棧的出棧元素是否與當(dāng)前最小值棧的棧頂元素一致,如果一致,最小值棧也彈出元素一次

當(dāng)想要獲取當(dāng)前棧中的最小元素時(shí),直接返回最小值棧的棧頂元素

如此,維護(hù)了兩個(gè)棧。

class MinStack {public Stack<Integer> stack;public Stack<Integer> minStack;public MinStack() {stack = new Stack<>();minStack = new Stack<>();}public void push(int val) {stack.push(val);if(minStack.empty() || minStack.peek() >= val) {minStack.push(val);}}public void pop() {if(stack.empty()) {return;}if(stack.pop().equals(minStack.peek())) {minStack.pop();}}public int top() {if(stack.empty()) {return -1;}return stack.peek();}public int getMin() {if(minStack.empty()) {return -1;}return minStack.peek();}
}

注意:

  • 最小值棧入棧的條件:當(dāng)入棧元素與當(dāng)前最小值棧的棧頂元素相等時(shí),也要入棧,相當(dāng)于有多個(gè)相等的最小值。

  • 這一條是筆者在解決該問題時(shí)出現(xiàn)的問題,如果我將pop()方法改成如下代碼,是否可行?

        public void pop() {if(stack.empty()) {return;}if(stack.pop() == minStack.peek()) {minStack.pop();}}
    

    不可行!

    因?yàn)?#xff0c;Stack類中的pop()peek()方法返回的是類型實(shí)參的類型,即實(shí)現(xiàn)泛型時(shí)<>里傳入的類型,是引用類型,如果像上面這樣書寫,本質(zhì)上是對(duì)兩個(gè)引用類型使用==比較,引用類型==比較的是地址,而不是值,所以不可行!

    但是,對(duì)于該題目,泛型實(shí)現(xiàn)時(shí)傳入的是Integer類型,通過==比較時(shí),可能會(huì)出現(xiàn)true的情況,這是因?yàn)?code>Integer有緩存機(jī)制

    緩存機(jī)制

    • Java對(duì)于Integer類型的對(duì)象在值位于-128到127之間時(shí)有特殊的緩存處理。JVM會(huì)為這個(gè)范圍的每個(gè)數(shù)字緩存一個(gè)Integer對(duì)象。

      例如,Integer a = 127; Integer b = 127; System.out.println(a == b); // 輸出 true,因?yàn)閍和b都指向同一個(gè)緩存的對(duì)象。

    • 對(duì)于超出該范圍的數(shù)字,即使值相同,也會(huì)創(chuàng)建不同的對(duì)象實(shí)例,所以==會(huì)比較返回false。

      Integer c = 128; Integer d = 128; System.out.println(c == d); // 輸出 false

    我們無法保證題目給出的值在緩存區(qū)間內(nèi),所以不可以像上面那樣書寫,我們可以使用equals方法判斷它們的值是否相等(就如答案所示),或者這么寫:

        public void pop() {if(stack.empty()) {return;}int tmp = stack.pop();if(tmp == minStack.peek()) {minStack.pop();}}
    

    上面這個(gè)代碼將Stack類中的pop方法的返回值用int類型的一個(gè)變量接收,返回值是Integer類型,所以會(huì)自動(dòng)拆箱為int類型,再用int類型與peek方法返回值的Integer類型使用==比較,而當(dāng)使用==比較Java中的Integer類型與int類型時(shí),會(huì)將Integer類型拆箱為int類型,所以本質(zhì)上是兩個(gè)int類型的比較,可行!

    原題鏈接:155. 最小棧 - 力扣(LeetCode)


幾個(gè)含"棧"概念的區(qū)分

區(qū)分、虛擬機(jī)棧棧幀

棧、虛擬機(jī)棧和棧幀是Java虛擬機(jī)(JVM)中的三個(gè)相關(guān)但不同的概念,它們?cè)?strong>定義功能、數(shù)據(jù)結(jié)構(gòu)以及生命周期等方面存在明顯的區(qū)別:

  1. 定義功能
    • Java棧:通常指的是一種后進(jìn)先出(LIFO)的數(shù)據(jù)結(jié)構(gòu),用于存儲(chǔ)程序執(zhí)行過程中的臨時(shí)數(shù)據(jù)。例如,方法的局部變量和返回地址等。
    • 虛擬機(jī)棧:特指JVM為每個(gè)線程分配的獨(dú)立內(nèi)存區(qū)域,用于存放棧幀,即方法調(diào)用的信息。它與線程同時(shí)創(chuàng)建和銷毀,主要支持方法的調(diào)用和執(zhí)行。
    • 棧幀:是虛擬機(jī)棧中的一個(gè)元素,對(duì)應(yīng)于正在執(zhí)行的每個(gè)方法。每個(gè)方法執(zhí)行時(shí)都會(huì)創(chuàng)建一個(gè)對(duì)應(yīng)的棧幀,包含局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接以及方法出口等信息。
  2. 數(shù)據(jù)結(jié)構(gòu)
    • Java棧:作為一種數(shù)據(jù)結(jié)構(gòu),其實(shí)現(xiàn)可以基于數(shù)組或鏈表,主要用于算法中數(shù)據(jù)的臨時(shí)存儲(chǔ)。
    • 虛擬機(jī)棧:作為JVM內(nèi)部的一個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū),其內(nèi)部由多個(gè)棧幀組成,每個(gè)棧幀對(duì)應(yīng)一個(gè)方法調(diào)用的相關(guān)信息。
    • 棧幀:具有固定的數(shù)據(jù)結(jié)構(gòu),包括局部變量表、操作數(shù)棧等,這些組成部分在編譯期間就已經(jīng)確定大小。
  3. 生命周期
    • Java棧:根據(jù)程序邏輯進(jìn)行入棧和出棧操作,使用完畢后即可銷毀。
    • 虛擬機(jī)棧:與線程綁定,線程結(jié)束時(shí)對(duì)應(yīng)的虛擬機(jī)棧也會(huì)被銷毀。
    • 棧幀:在方法調(diào)用時(shí)創(chuàng)建,方法執(zhí)行完畢或異常終止時(shí)銷毀。
  4. 存儲(chǔ)內(nèi)容
    • Java棧:可用于存儲(chǔ)任何類型的對(duì)象,如基本類型、引用類型等。
    • 虛擬機(jī)棧:專門用于存儲(chǔ)方法調(diào)用的相關(guān)信息,如局部變量、操作數(shù)等。
    • 棧幀:具體存儲(chǔ)了方法的局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接以及方法的返回地址等信息。
  5. 應(yīng)用場(chǎng)景
    • Java棧:廣泛應(yīng)用于各類算法中,如深度優(yōu)先搜索、遞歸計(jì)算等。
    • 虛擬機(jī)棧:在JVM的執(zhí)行引擎中應(yīng)用,用于支持方法的調(diào)用和執(zhí)行。
    • 棧幀:直接關(guān)聯(lián)到每個(gè)方法的具體執(zhí)行過程,記錄了方法執(zhí)行所需的全部信息。

總的來說,Java棧、虛擬機(jī)棧和棧幀各自承擔(dān)著不同的功能和角色。Java棧是一個(gè)通用的數(shù)據(jù)結(jié)構(gòu),而虛擬機(jī)棧和棧幀則是JVM內(nèi)部專門設(shè)計(jì)的機(jī)制,用于支持方法的調(diào)用和執(zhí)行。這三者共同協(xié)作,確保了Java程序能夠高效、安全地運(yùn)行。


隊(duì)列

基本概念

隊(duì)列是只允許在一端進(jìn)行插入數(shù)據(jù)操作,在另一端進(jìn)行刪除數(shù)據(jù)操作的特殊線性表,其特點(diǎn)概括為 先進(jìn)先出,就像現(xiàn)實(shí)生活中的排隊(duì)一樣,在最早排隊(duì)的總是先出隊(duì)。

隊(duì)頭:進(jìn)行刪除操作的一端;隊(duì)尾:進(jìn)行插入操作的一端

在這里插入圖片描述

注意區(qū)分棧和隊(duì)列。


隊(duì)列的模擬實(shí)現(xiàn)

了解了隊(duì)列的基本概念后,思考怎樣實(shí)現(xiàn)一個(gè)隊(duì)列?使用數(shù)組還是鏈表?

假設(shè)使用數(shù)組,通常我們會(huì)定義一個(gè)隊(duì)頭變量和隊(duì)尾變量,以方便入隊(duì)和出隊(duì)操作,入隊(duì)操作使用尾插,那么出隊(duì)操作就必須是頭刪。當(dāng)隊(duì)列不為空,每次出隊(duì),隊(duì)頭變量要不斷地向后移動(dòng),最終會(huì)導(dǎo)致數(shù)組的前半部分空間都被浪費(fèi)了,且隊(duì)列容量越來越少,所以簡(jiǎn)單的數(shù)組實(shí)現(xiàn)隊(duì)列是不方便的,如果要使用數(shù)組,那么最好實(shí)現(xiàn)成循環(huán)隊(duì)列(后面會(huì)講)。

一般來說,隊(duì)列使用鏈表實(shí)現(xiàn),問題是入隊(duì)和出隊(duì)操作怎么實(shí)現(xiàn)?對(duì)于單鏈表,定義兩個(gè)引用,分別指向隊(duì)頭和隊(duì)尾,如果出隊(duì)采用尾刪,那么我們就得遍歷鏈表找到倒數(shù)第二個(gè)結(jié)點(diǎn),讓它的nextnull,效率較低,所以出隊(duì)采用頭刪,相應(yīng)地,入隊(duì)采用尾插,從而達(dá)到"先進(jìn)先出"的特點(diǎn),并且保證了入隊(duì)和出隊(duì)的時(shí)間復(fù)雜度都是O(1)

但如果是雙向鏈表,那么就不需要考慮上面的問題,入隊(duì)出隊(duì)操作都是O(1),我們這里采用雙向鏈表模擬實(shí)現(xiàn)一個(gè)隊(duì)列:

實(shí)現(xiàn)如下(雙向鏈表的頭刪、尾插操作,較為簡(jiǎn)單):

public class MyQueue {//鏈表結(jié)點(diǎn)類static class ListNode {public int val;public ListNode prev;public ListNode next;public ListNode(int val) {this.val = val;}}public ListNode head;//隊(duì)頭引用public ListNode tail;//隊(duì)尾引用private int size;//隊(duì)列有效元素個(gè)數(shù)//入隊(duì)public void offer(int data) {ListNode newNode = new ListNode(data);if(tail == null) {head = newNode;tail = newNode;size++;return;}tail.next = newNode;newNode.prev = tail;tail = newNode;size++;}//出隊(duì)并返回出隊(duì)元素public int poll() {if(this.head == null) {throw new QueueIsEmptyException("The Queue Is Empty!: 隊(duì)列為空!");}int ret = head.val;if(head == tail) {head = null;tail = null;}else {head.next.prev = null;head = head.next;}size--;return ret;}//獲取隊(duì)頭元素public int peek() {if(this.head == null) {throw new QueueIsEmptyException("The Queue Is Empty!: 隊(duì)列為空!");}return this.head.val;}//獲取隊(duì)列中的有效元素個(gè)數(shù)public int size() {return this.size;}//判斷隊(duì)列是否為空public boolean isEmpty() {return this.head == null;}}

循環(huán)隊(duì)列

前面提到,單純的數(shù)組實(shí)現(xiàn)隊(duì)列會(huì)導(dǎo)致空間的浪費(fèi)以及隊(duì)列大小的縮減,這時(shí)候引出了循環(huán)隊(duì)列的概念:

循環(huán)隊(duì)列是一種優(yōu)化的隊(duì)列數(shù)據(jù)結(jié)構(gòu),旨在解決順序隊(duì)列中存在的“假溢出”問題。

循環(huán)隊(duì)列采用了頭尾相接的環(huán)狀存儲(chǔ)結(jié)構(gòu),通過將順序隊(duì)列的數(shù)組視為一個(gè)循環(huán)結(jié)構(gòu),使得當(dāng)存儲(chǔ)空間的最后一個(gè)位置已被使用時(shí),新元素可以繼續(xù)從第一個(gè)位置開始存儲(chǔ),形成一個(gè)邏輯上的環(huán)。這種設(shè)計(jì)極大地提高了存儲(chǔ)空間的利用率。

接下來我們就講解一下循環(huán)隊(duì)列的思想,關(guān)于循環(huán)隊(duì)列,我們要解決兩大問題:

當(dāng)存儲(chǔ)空間的最后一個(gè)位置已被使用時(shí),新元素怎樣繼續(xù)從第一個(gè)位置開始存儲(chǔ)?

怎樣區(qū)分循環(huán)隊(duì)列的 空 和 滿 兩個(gè)狀態(tài)?


【問題一】

在實(shí)現(xiàn)循環(huán)隊(duì)列時(shí),我們?nèi)匀粫?huì)定義兩個(gè)"指針":rear(指向隊(duì)尾,這個(gè)隊(duì)尾實(shí)際上是下一次入隊(duì)的位置,而不是指隊(duì)尾元素)、front(指向隊(duì)頭,即隊(duì)頭元素),于是就可能會(huì)出現(xiàn)下圖的情況:

在這里插入圖片描述

此時(shí),存儲(chǔ)空間的最后一個(gè)位置已被使用,rear指向了最后位置后面的一個(gè)位置(此位置不能入新元素了),而此時(shí)由于進(jìn)行過出隊(duì)操作,數(shù)組的前面還有剩余空間可以使用,我們就得想辦法讓空閑空間被利用到,即讓rear重新回到數(shù)組開始的位置,怎么辦?

傳統(tǒng)的rear += 1肯定不行,我們采用這樣的語句 rear = (rear + 1) % lenlen就是數(shù)組長(zhǎng)度。對(duì)于上面的情況,我們代入公式:

rear = (8 + 1) % 9,得到0,此時(shí)rear就重新回到了數(shù)組0下標(biāo)位置,這個(gè)公式在任何位置都是可以的。有了這個(gè)公式,frontrear就可以循環(huán)起來了。


【問題二】

怎樣區(qū)分循環(huán)隊(duì)列的 空 和 滿 兩個(gè)狀態(tài)? 我們看如下圖表示的情況,為了突出循環(huán),我們將數(shù)組在視覺上改成環(huán):
在這里插入圖片描述

在這里插入圖片描述

圖1表示隊(duì)列為空,圖2表示隊(duì)列已滿,但是兩種情況下都是rear == front,怎么區(qū)分呢?

我們有三種解決方案:

  • 定義成員變量size表示隊(duì)列中的有效元素個(gè)數(shù):當(dāng)size和數(shù)組長(zhǎng)度相等時(shí),表示滿;為0時(shí)表示空
  • 定義一個(gè)boolean類型的標(biāo)記:最開始為false,當(dāng)入隊(duì)新元素后變?yōu)?code>true,當(dāng)出隊(duì)元素后rear == front,說明最后一個(gè)元素出隊(duì)了,將其置為false。這樣,當(dāng)rear == front && 標(biāo)記為false時(shí),表示空,當(dāng)rear == front && 標(biāo)記為true時(shí),表示滿
  • 浪費(fèi)一個(gè)空間:即留出一個(gè)空間不放元素,當(dāng)rear == front時(shí),表示空;當(dāng)(rear + 1) % len == front(下一個(gè)位置是隊(duì)頭)時(shí),表示滿

解決完上面的兩個(gè)問題,我們以第二種解決方案動(dòng)手實(shí)現(xiàn)一下,(分析與注意事項(xiàng)在代碼后面):

public class CircularQueue {public int[] elem;//數(shù)組private boolean flag;//標(biāo)記public int rear;//隊(duì)尾指針public int front;//隊(duì)頭指針public CircularQueue() {elem = new int[10];}public void offer(int data) {if(rear == front && flag == true) {System.out.println("隊(duì)列已滿");return;}elem[rear] = data;rear = (rear + 1) % elem.length;flag = true;}public int poll() {if(isEmpty()) {throw new QueueIsEmptyException("The Queue Is Empty!: 隊(duì)列為空!");}int ret = elem[front];front = (front + 1) % elem.length;if(rear == front) {flag = false;}return ret;}public int peek() {if(isEmpty()) {throw new QueueIsEmptyException("The Queue Is Empty!: 隊(duì)列為空!");}return elem[front];}public int size() {if(rear > front) {return rear - front;}else if(rear < front) {return rear + (elem.length - front);}else {return flag == true ? elem.length : 0;}}public boolean isEmpty() {return rear == front && flag == false;}
}
  • rear實(shí)際上指向下一次入隊(duì)的位置,而不是指向隊(duì)尾元素;而front是指向隊(duì)頭元素
  • offer方法最后一定要將標(biāo)記置為true
  • poll方法內(nèi)部在front因出隊(duì)改變后,要檢查是否要將標(biāo)記置為false,即檢查該次出隊(duì)的是否是隊(duì)列中最后一個(gè)元素
  • size方法考慮的就比較多了,循環(huán)隊(duì)列的思想導(dǎo)致rearfront的相對(duì)位置會(huì)發(fā)生變化,如代碼:分為rear > front、rear < front以及rear == front,特別注意第三種相等的情況,可能是滿了,也可能是空,這要根據(jù)標(biāo)記判斷。

不妨做個(gè)練習(xí),嘗試使用問題二中的其他方案設(shè)計(jì)循環(huán)隊(duì)列:

class MyCircularQueue {public MyCircularQueue(int k) {}public boolean enQueue(int value) {}public boolean deQueue() {}public int Front() {}public int Rear() {}public boolean isEmpty() {}public boolean isFull() {}
}

給出以浪費(fèi)一個(gè)空間方案完成該題目的代碼:

class MyCircularQueue {public int[] elem;public int front;public int rear;public MyCircularQueue(int k) {elem = new int[k + 1];}public boolean enQueue(int value) {if(isFull()) {return false;}elem[rear] = value;rear = (rear + 1) % elem.length;return true;}public boolean deQueue() {if(isEmpty()) {return false;}front = (front + 1) % elem.length;return true;}public int Front() {if(isEmpty()) {return -1;}return elem[front];}public int Rear() {if(isEmpty()) {return -1;}if(rear == 0) {return elem[elem.length - 1];}return elem[rear - 1];}public boolean isEmpty() {return rear == front;}public boolean isFull() {return (rear + 1) % elem.length == front;}
}
  • 既然要浪費(fèi)一個(gè)空間,那么我們?cè)跇?gòu)造方法初始化數(shù)組時(shí)要?jiǎng)?chuàng)建一個(gè)比參數(shù)大1個(gè)空間的數(shù)組,保證一部分測(cè)試用例能夠順利通過。
  • Rear方法要求返回隊(duì)尾元素,由于我們的rear是隊(duì)尾元素之后的一個(gè)位置,所以我們必須向前一個(gè)位置找,這里就有一個(gè)特殊情況,當(dāng)rear == 0,此時(shí)不能減一,前一個(gè)應(yīng)該是數(shù)組最后一個(gè)下標(biāo)的位置,所以有如上代碼。

原題鏈接:622. 設(shè)計(jì)循環(huán)隊(duì)列 - 力扣(LeetCode)


雙端隊(duì)列

雙端隊(duì)列(deque)是指允許兩端都可以進(jìn)行入隊(duì)和出隊(duì)操作的隊(duì)列,deque 是 “double ended queue” 的簡(jiǎn)稱。 那就說明元素可以從隊(duì)頭出隊(duì)和入隊(duì),也可以從隊(duì)尾出隊(duì)和入隊(duì)。

雙端隊(duì)列 - youngliu91 - 博客園

在集合框架中,雙端隊(duì)列對(duì)應(yīng)Deque接口,在實(shí)際工程中,使用Deque接口是比較多的,棧和隊(duì)列均可以使用該接口。

實(shí)現(xiàn)雙端隊(duì)列可以用LinkedList(鏈?zhǔn)綄?shí)現(xiàn))或ArrayDeque(線性實(shí)現(xiàn)):

    public static void main(String[] args) {Deque<Integer> deque1 = new LinkedList<>();//鏈?zhǔn)綄?shí)現(xiàn)Deque<Integer> deque2 = new ArrayDeque<>();//線性實(shí)現(xiàn)}

所以,到這里我們發(fā)現(xiàn):

LinkedList可以作為鏈表、棧、(普通)隊(duì)列、雙端隊(duì)列

ArrayList可以作為棧、(普通)隊(duì)列、雙端隊(duì)列


集合框架中的隊(duì)列

集合框架中的隊(duì)列是Queue接口,Deque接口繼承自它,LinkedListArrayDeque都實(shí)現(xiàn)了該接口。

在這里插入圖片描述

隊(duì)列的創(chuàng)建

我們可以通過ArrayDeque或者LinkedList創(chuàng)建一個(gè)隊(duì)列:

    public static void main(String[] args) {Queue<Integer> queue1 = new LinkedList<>();//鏈?zhǔn)疥?duì)列Queue<Integer> queue2 = new ArrayDeque<>();//線性隊(duì)列}

隊(duì)列的方法
方法功能
boolean offer(E e)入隊(duì)列
E poll()出隊(duì)列
E peek()獲取隊(duì)頭元素
int size()獲取隊(duì)列中有效元素個(gè)數(shù)
boolean isEmpty()檢測(cè)隊(duì)列是否為空

隊(duì)列的遍歷
    public static void main(String[] args) {Queue<Integer> queue1 = new LinkedList<>();queue1.offer(1);queue1.offer(2);queue1.offer(3);queue1.offer(4);queue1.offer(5);System.out.println("=====for-each=====");for(Integer x : queue1) {System.out.print(x + " ");}System.out.println();System.out.println("=====迭代器=====");Iterator<Integer> it = queue1.iterator();while(it.hasNext()) {System.out.print(it.next() + " ");}System.out.println();System.out.println("=====while=====");while(!queue1.isEmpty()) {System.out.print(queue1.poll() + " ");}System.out.println();}

在這里插入圖片描述


隊(duì)列的應(yīng)用及相關(guān)練習(xí)

用隊(duì)列實(shí)現(xiàn)棧

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

class MyStack {public MyStack() {}public void push(int x) {}public int pop() {}public int top() {}public boolean empty() {}
}

【思路】

以畫圖+文字介紹:

在這里插入圖片描述

現(xiàn)在我們要模擬出棧,如圖向棧中依次加入21、56、23、11,此時(shí)棧頂元素應(yīng)為11,出棧時(shí)要彈出11。

我們只有兩個(gè)隊(duì)列,所以讓不為空的隊(duì)列中的元素出隊(duì),直到只剩1個(gè)元素,這個(gè)元素就是"棧頂"元素,將它"彈出";此時(shí)如果再次入隊(duì)

在這里插入圖片描述

此時(shí),如果再添加新元素,繼續(xù)向非空隊(duì)列添加,而它就是新的"棧頂元素",如果接著"出棧",就重復(fù)上面的工作:將元素出隊(duì)到空隊(duì)列,直到只剩一個(gè)元素,彈出。

所以有:

入棧: 向非空隊(duì)列中添加元素,初始都為空時(shí)隨意選擇

出棧: 非空隊(duì)列將元素出到空隊(duì)列中,直到只剩下一個(gè)元素,這個(gè)元素就是棧頂元素,彈出

class MyStack {public Queue<Integer> q1;public Queue<Integer> q2;public MyStack() {q1 = new LinkedList<>();q2 = new LinkedList<>();}public void push(int x) {if(!q1.isEmpty()) {q1.offer(x);}else if(!q2.isEmpty()){q2.offer(x);}else{q1.offer(x);}}public int pop() {if(empty()) {return -1;}if(!q1.isEmpty()) {int size = q1.size();for(int i = 0; i < size - 1; i++) {q2.offer(q1.poll());}return q1.poll();}else{int size = q2.size();for(int i = 0; i < size - 1; i++) {q1.offer(q2.poll());}return q2.poll();}}public int top() {if(empty()) {return -1;}if(!q1.isEmpty()) {int size = q1.size();int ret = 0;for(int i = 0; i < size; i++) {ret = q1.poll();q2.offer(ret);}return ret;}else{int size = q2.size();int ret = 0;for(int i = 0; i < size; i++) {ret = q2.poll();q1.offer(ret);}return ret;}}public boolean empty() {return q1.isEmpty() && q2.isEmpty();}
}

原題鏈接:225. 用隊(duì)列實(shí)現(xiàn)棧 - 力扣(LeetCode)


用棧實(shí)現(xiàn)隊(duì)列

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

class MyQueue {public MyQueue() {}public void push(int x) {}public int pop() {}public int peek() {}public boolean empty() {}
}

【思路】

在這里插入圖片描述

如上圖,如果不再添加新元素,按照?qǐng)D解思路出隊(duì),得到序列:[10, 44, 31, 12, 101, 88, 36],滿足隊(duì)列的先進(jìn)先出。

class MyQueue {public Stack<Integer> sIn;public Stack<Integer> sOut;public MyQueue() {sIn = new Stack<>();sOut = new Stack<>();}public void push(int x) {sIn.push(x);}public int pop() {if(empty()) {return -1;}if(sOut.empty()) {while(!sIn.empty()) {sOut.push(sIn.pop());}}return sOut.pop();}public int peek() {if(empty()) {return -1;}if(sOut.empty()) {while(!sIn.empty()) {sOut.push(sIn.pop());}}return sOut.peek();}public boolean empty() {return sIn.empty() && sOut.empty();}
}

原題鏈接:232. 用棧實(shí)現(xiàn)隊(duì)列 - 力扣(LeetCode)


http://www.risenshineclean.com/news/60014.html

相關(guān)文章:

  • 網(wǎng)站里的搜索怎么做免費(fèi)制作自己的網(wǎng)站
  • 西安本地十家做網(wǎng)站建設(shè)的公司seo網(wǎng)站排名的軟件
  • 醫(yī)學(xué)院英文網(wǎng)站建設(shè)方案廣州網(wǎng)絡(luò)推廣哪家好
  • 上海網(wǎng)站開發(fā)哪里有外鏈發(fā)布網(wǎng)站
  • 如何在vs做網(wǎng)站免費(fèi)線上培訓(xùn)平臺(tái)
  • 關(guān)于政府網(wǎng)站建設(shè)的幾點(diǎn)建議免費(fèi)個(gè)人網(wǎng)頁制作
  • 蕭山城區(qū)建設(shè)有限公司網(wǎng)站公司官網(wǎng)制作多少錢
  • 做網(wǎng)站有沒有受騙過免費(fèi)刷贊網(wǎng)站推廣免費(fèi)
  • 網(wǎng)站建設(shè)費(fèi)怎么做分錄seo案例視頻教程
  • 昆明網(wǎng)站建設(shè)服務(wù)html網(wǎng)頁制作app
  • 網(wǎng)頁制作網(wǎng)站平臺(tái)深圳網(wǎng)絡(luò)推廣網(wǎng)絡(luò)
  • 中國(guó)數(shù)學(xué)外國(guó)人做視頻網(wǎng)站網(wǎng)絡(luò)軟件開發(fā)
  • 買完域名后如何建設(shè)網(wǎng)站seo基礎(chǔ)課程
  • 維度 網(wǎng)站建設(shè)什么是軟文寫作
  • wordpress默認(rèn)logo圖片路徑佛山seo關(guān)鍵詞排名
  • 中國(guó)建設(shè)銀行吉林省分行官網(wǎng)站電子商務(wù)
  • 網(wǎng)頁設(shè)計(jì)技術(shù)論文青島seo關(guān)鍵字排名
  • php網(wǎng)站開發(fā)實(shí)踐太原百度公司地址
  • 品牌網(wǎng)站建設(shè)哪好商丘關(guān)鍵詞優(yōu)化推廣
  • 天津做網(wǎng)站聯(lián)系方式優(yōu)化關(guān)鍵詞首頁排行榜
  • html5建站系統(tǒng)線下推廣方式有哪些
  • 網(wǎng)站qq在線客服代碼怎么安裝快速網(wǎng)站seo效果
  • 10大最佳免費(fèi)建站軟件推薦網(wǎng)站競(jìng)價(jià)推廣怎么做
  • 國(guó)外哪個(gè)網(wǎng)站做服裝百度怎么免費(fèi)推廣
  • wordpress適合大型網(wǎng)站嗎類似凡科建站的平臺(tái)
  • 四川成都網(wǎng)站優(yōu)化百度快速排名技術(shù)培訓(xùn)教程
  • 關(guān)于做網(wǎng)站常見的問題西安seo優(yōu)化公司
  • 濟(jì)寧網(wǎng)站建設(shè)神華關(guān)鍵詞優(yōu)化包含
  • 有哪些網(wǎng)站有收錄做紅酒的商行杭州網(wǎng)絡(luò)整合營(yíng)銷公司
  • 永久免費(fèi)網(wǎng)站搭建山東網(wǎng)絡(luò)推廣網(wǎng)站