A01-棧和隊(duì)列

自學(xué)筆記:《數(shù)據(jù)結(jié)構(gòu)與算法基礎(chǔ)》-第1篇——棧和隊(duì)列(基于C語言)


一、基本概念

  • 棧(Stack):一種特殊的線性表,限定僅在一端(表尾)進(jìn)行插入和刪除操作的線性表。
  • 表尾(an端)稱為棧頂(Top),表頭(a1)稱為棧底(Base),插入元素到棧頂?shù)牟僮鞣Q為入棧,刪除棧頂最后一個(gè)元素稱為出棧,入 = 壓入 = Push,出 = 彈出 = Pop
  • 邏輯結(jié)構(gòu):同線性表相同,一對(duì)一關(guān)系
  • 存儲(chǔ)結(jié)構(gòu):順序棧、鏈?zhǔn)綏?/li>
  • 運(yùn)算規(guī)則:后進(jìn)先出(LIFO)

隊(duì)列

  • 隊(duì)列(Queue):一種特殊的線性表,限定僅在一端(表尾)進(jìn)行插入操作,在另一端(表頭)進(jìn)行刪除操作的線性表(頭刪尾插)。
  • 表尾(an端)稱為隊(duì)尾,表頭a1端稱為隊(duì)頭,插入元素稱為入隊(duì),刪除元素稱為出隊(duì)
  • 邏輯結(jié)構(gòu):同線性表相同,一對(duì)一關(guān)系
  • 存儲(chǔ)結(jié)構(gòu):順序隊(duì)(循環(huán)順序隊(duì)列更常見)、鏈隊(duì)
  • 運(yùn)算規(guī)則:先進(jìn)先出(FIFO)

二、抽象數(shù)據(jù)類型

\small \color {rgb(70,130,180)}{ADT \ Stack}{
\small \quad \color {rgb(255,99,71)}{數(shù)據(jù)對(duì)象:} \quad \color{rgb(70,130,180)}{D = {a_i \,|\, a_i \in ElemSet, \ i=1,2,...,n, \ n \geq 0}}
\small \quad \color {rgb(255,99,71)}{數(shù)據(jù)關(guān)系:} \quad \color{rgb(70,130,180)}{R_1 = {<a_{i-1} \,,\, a_i> |\, a_{i-1},a_i \in D, \ i=2,...,n}}
\qquad \qquad \qquad \small \color {rgb(70,130,180)}{約定a_n端為棧頂,a_1端為棧底}
\small \quad \color {rgb(255,99,71)}{基本操作:} \quad \color{ rgb(70,130,180)}{ 初始化、進(jìn)棧、出棧、取棧頂元素等}
\small }\color {rgb(70,130,180)}{ADT \ Stack}

基本操作
  1. 初始化順序棧:InitStack(*S)
    操作結(jié)果:構(gòu)造一個(gè)空棧S。
  2. 銷毀順序棧:DestroyStack(*S)
    初始條件:棧S已存在。
    操作結(jié)果:棧S被銷毀。
  3. 清空順序棧:ClearStack(*S)
    初始條件:棧S已存在。
    操作結(jié)果:將S清為空棧。
  4. 判斷是否為空棧:StackEmpty(S)
    初始條件:棧S已存在。
    操作結(jié)果:若棧S為空棧,則返回TRUE,否則FALSE。
  5. 求棧的長(zhǎng)度:StackLength(S)
    初始條件:棧S已存在。
    操作結(jié)果:返回S的元素個(gè)數(shù),即棧的長(zhǎng)度。
  6. 入棧操作:Push(*S,e)
    初始條件:棧S已存在。
    操作結(jié)果:插入元素e為新的棧頂元素。
  7. 出棧操作:Pop(*S,*e)
    初始條件:棧S已存在且非空。
    操作結(jié)果:刪除S的棧頂元素an,并用e返回其值。
  8. 取棧頂元素:GetTop(S,*e)
    初始條件:棧S已存在且非空。
    操作結(jié)果:用e返回S的棧頂元素。

隊(duì)列

\small \color {rgb(70,130,180)}{ADT \ Queue}{
\small \quad \color {rgb(255,99,71)}{數(shù)據(jù)對(duì)象:} \quad \color{rgb(70,130,180)}{D = {a_i \,|\, a_i \in ElemSet, \ i=1,2,...,n, \ n \geq 0}}
\small \quad \color {rgb(255,99,71)}{數(shù)據(jù)關(guān)系:} \quad \color{rgb(70,130,180)}{R_1 = {<a_{i-1} \,,\, a_i> |\, a_{i-1},a_i \in D, \ i=2,...,n}}
\qquad \qquad \qquad \small \color {rgb(70,130,180)}{約定a_1端為隊(duì)列頭,a_n端為隊(duì)列尾}
\small \quad \color {rgb(255,99,71)}{基本操作:} \quad \color{rgb(70,130,180)}{初始化、入隊(duì)、出隊(duì)、取隊(duì)頭元素等}
\small }\color {rgb(70,130,180)}{ADT \ Queue}

基本操作
  1. 初始化隊(duì)列:InitQueue(*Q)
    操作結(jié)果:構(gòu)造一個(gè)空隊(duì)列Q。
  2. 銷毀隊(duì)列:DestroyQueue(*Q)
    初始條件:隊(duì)列Q已存在。
    操作結(jié)果:隊(duì)列Q被銷毀。
  3. 清空隊(duì)列:ClearQueue(*Q)
    初始條件:隊(duì)列Q已存在。
    操作結(jié)果:將Q清為空隊(duì)列。
  4. 判斷是否為空隊(duì)列:QueueEmpty(Q)
    初始條件:隊(duì)列Q已存在。
    操作結(jié)果:若隊(duì)列Q為空隊(duì)列,則返回TRUE,否則FALSE。
  5. 求隊(duì)列的長(zhǎng)度:QueueLength(Q)
    初始條件:隊(duì)列Q已存在。
    操作結(jié)果:返回Q的元素個(gè)數(shù),即隊(duì)列的長(zhǎng)度。
  6. 入隊(duì)列操作:EnQueue(*Q,e)
    初始條件:隊(duì)列Q已存在。
    操作結(jié)果:插入元素e為新的隊(duì)尾元素。
  7. 出隊(duì)列操作:DeQueue(*Q,*e)
    初始條件:隊(duì)列Q已存在且非空。
    操作結(jié)果:刪除Q的隊(duì)頭元素an,并用e返回其值。
  8. 取隊(duì)頭元素:GetHead(Q,*e)
    初始條件:隊(duì)列Q已存在且非空。
    操作結(jié)果:用e返回Q的隊(duì)頭元素。

三、棧的C語言表示和實(shí)現(xiàn)

棧的順序表示

  • 利用一組地址連續(xù)的存儲(chǔ)單元依次存放自棧底到棧頂?shù)臄?shù)據(jù)元素,棧底一般在低地址端。附設(shè)top指針,指向棧頂元素在順序棧中的位置,附設(shè)base指針,指向棧底元素在順序棧中的位置
  • 為了方便操作,通常top指向棧頂元素之后的下標(biāo)地址。用stacksize表示??墒褂玫淖畲笕萘?/li>
  • 空棧:base == top,棧空標(biāo)志;棧滿:top-base == stacksize,棧滿標(biāo)志
  • 棧滿時(shí)的處理方法:
    1. 報(bào)錯(cuò),返回操作系統(tǒng)。
    2. 分配更大的空間,作為棧的存儲(chǔ)空間,將原棧內(nèi)容移入新棧

順序棧的實(shí)現(xiàn)

//數(shù)據(jù)結(jié)構(gòu)與算法分析-棧-順序?qū)崿F(xiàn)
#include<stdio.h>
#include<stdlib.h>

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1  //不可實(shí)現(xiàn)
#define OVERFLOW -2  //溢出

#define MAXSIZE 100  //長(zhǎng)度

typedef int value;  //返回值類型
typedef int status;  //返回狀態(tài)類型
typedef int elemtype;  //元素類型

typedef struct
{
    elemtype *base;  //棧底指針
    elemtype *top;  //棧頂指針
    int stacksize;  //??捎米畲笕萘?}SqStack;

status initstack(SqStack *s);  //順序棧的初始化
status stackempty(SqStack s);  //判斷棧是否為空
value stacklength(SqStack s);  //返回順序棧長(zhǎng)度
status clearstack(SqStack s);  //清空順序棧
status destroystack(SqStack *s);  //銷毀順序渣
status push(SqStack *s,elemtype e);  //入棧
status pop(SqStack *s,elemtype *e);  //出棧

int main()
{
    printf("\n測(cè)試\n");
//  system("pause");
    return 0;
}
status initstack(SqStack *s)
{
    s->base = (elemtype*)malloc(MAXSIZE*sizeof(elemtype));
    if(!s->base)
        exit(OVERFLOW);
    s->top = s->base;
    s->stacksize = MAXSIZE;
    return OK;
}
status stackempty(SqStack s)
{
    if(s.top == s.top)
        return TRUE;
    else
        return FALSE;
}
value stacklength(SqStack s)
{
    return s.top-s.base;
}
status clearstack(SqStack s)
{
    if(s.base)
        s.top = s.base;
    return OK;
}
status destroystack(SqStack *s)
{
    if(s->base)
    {
        free(s->base);
        s->stacksize = 0;
        s->base = NULL;
        s->top = NULL;
    }
    return OK;
}
status push(SqStack *s,elemtype e)
{
    if(s->top - s->base == s->stacksize)
        return ERROR;
    *s->top++ = e;  //*(s->top)=e;s->top++;
    return OK;
}
status pop(SqStack *s,elemtype *e)
{
    if(s->top == s->base)
        return ERROR;
    *e = *--s->top;  //--s->top;*e = *s->top;
    return OK;
}

棧的鏈?zhǔn)奖硎?/h4>
  • 使用數(shù)組作為順序棧存儲(chǔ)方式的特點(diǎn):簡(jiǎn)單、方便、但易產(chǎn)生溢出(數(shù)組大小固定)
  • 上溢(overflow):棧已經(jīng)滿,又要壓入元素;下溢(underflow):棧已經(jīng)空,還要彈出元素
    注:上溢是一種錯(cuò)誤,使問題的處理無法進(jìn)行;而下溢一般認(rèn)為是一種結(jié)束條件,即問題處理結(jié)束。
  • 鏈表的頭指針就是棧頂;不需要頭結(jié)點(diǎn);基本不存在棧滿的情況;空棧相當(dāng)于頭指針指向空

鏈棧的實(shí)現(xiàn)

//數(shù)據(jù)結(jié)構(gòu)與算法分析-棧-鏈?zhǔn)綄?shí)現(xiàn)
#include<stdio.h>
#include<stdlib.h>

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1  //不可實(shí)現(xiàn)
#define OVERFLOW -2  //溢出

#define MAXSIZE 100  //長(zhǎng)度

typedef int value;  //返回值類型
typedef int status;  //返回狀態(tài)類型
typedef int elemtype;  //元素類型

typedef struct StackNode
{
    elemtype data;
    struct StackNode *next;
}StackNode,*LinkStack;

status initstack(LinkStack *s);  //鏈棧初始化
status stackempty(LinkStack s);  //判斷鏈棧是否為空
status push(LinkStack *s,elemtype e);  //入棧
status pop(LinkStack *s,elemtype *e);  //出棧
elemtype gettop(LinkStack s);  //返回鏈棧棧頂元素

int main()
{
    printf("\n測(cè)試\n");
//  system("pause");
    return 0;
}
status initstack(LinkStack *s)
{
    *s = NULL;
    return OK;
}
status stackempty(LinkStack s)
{
    if(s == NULL)
        return TRUE;
    return FALSE;
}
status push(LinkStack *s,elemtype e)
{
    StackNode *p = (StackNode*)malloc(sizeof(StackNode));
    p->data = e;
    p->next = *s;
    *s = p;
    return OK;
}
status pop(LinkStack *s,elemtype *e)
{
    if(s == NULL)
        return ERROR;
    *e = (*s)->data;
    StackNode *p;
    p = *s;
    *s = (*s)->next;
    free(p);
    return OK;
}
elemtype gettop(LinkStack s)
{
    if(s != NULL)
        return s->data;
}

棧與遞歸

  • 遞歸:若一個(gè)對(duì)象部分地包含它自己,或用它自己給自己定義,則稱這個(gè)對(duì)象是遞歸的;若一個(gè)過程直接地或者間接地調(diào)用自己,則稱這個(gè)過程是遞歸的過程。
  • 以下三種情況常常用到遞歸方法:
    1.遞歸定義的數(shù)學(xué)函數(shù)。2.具有遞歸特性的數(shù)據(jù)結(jié)構(gòu)。3.可遞歸求解的問題。
  • 遞歸問題——用分治法求解
    分治法:對(duì)于一個(gè)較為復(fù)雜的問題,能夠分解成幾個(gè)相對(duì)簡(jiǎn)單的且解法相同或類似的子問題來求解。
  • 必備的三個(gè)條件:
    1.能夠?qū)⒁粋€(gè)問題轉(zhuǎn)變成一個(gè)新問題,而新問題與原問題的解法相同或類同,不同的僅是處理的對(duì)象,且這些處理對(duì)象是變化有規(guī)律的。
    2.可以通過上述轉(zhuǎn)化使問題簡(jiǎn)化。
    3.必須有一個(gè)明確的遞歸出口,或稱遞歸的邊界。
  • 分治法求解遞歸問題算法的一般形式:
void p(參數(shù)表)
{
    if (遞歸結(jié)束條件)  可直接求解步驟;  //------基本項(xiàng)
    else p(較小的參數(shù));  //------歸納項(xiàng)
}
  • 函數(shù)調(diào)用過程
    調(diào)用前,系統(tǒng)完成:
    (1)將實(shí)參、返回地址等傳遞給被調(diào)用函數(shù)。
    (2)為被調(diào)用函數(shù)的局部變量分配存儲(chǔ)區(qū)。
    (3)將控制轉(zhuǎn)移到被調(diào)用函數(shù)的入口。
    調(diào)用后,系統(tǒng)完成:
    (1)保存被調(diào)用函數(shù)的計(jì)算結(jié)果。
    (2)釋放被調(diào)用函數(shù)的數(shù)據(jù)區(qū)。
    (3)依照被調(diào)用函數(shù)保存的返回地址將控制轉(zhuǎn)移到調(diào)用函數(shù)。
  • 當(dāng)多個(gè)函數(shù)構(gòu)成嵌套調(diào)用時(shí):遵循后調(diào)用的先返回------棧
    “層次”-函數(shù)嵌套
    “遞歸工作站”-遞歸程序運(yùn)行期間使用的數(shù)據(jù)存儲(chǔ)區(qū)
    “工作記錄”-實(shí)參,局部變量,返回地址
  • 遞歸的優(yōu)缺點(diǎn):
    優(yōu)點(diǎn):結(jié)構(gòu)清晰,程序易讀。
    缺點(diǎn):每次調(diào)用要生成工作記錄,保存狀態(tài)信息,入棧;返回時(shí)要出棧,恢復(fù)狀態(tài)信息,時(shí)間開銷大。
  • 遞歸->非遞歸的方法:
    1.(尾遞歸、單向遞歸)->變成循環(huán)結(jié)構(gòu)。
    2.自用棧模擬系統(tǒng)的運(yùn)行時(shí)棧。
  • 借助棧改寫遞歸
    遞歸程序在執(zhí)行時(shí)需要系統(tǒng)提供棧來實(shí)現(xiàn)。
    仿照遞歸算法執(zhí)行過程中遞歸工作棧的狀態(tài)變化可寫出相應(yīng)的非遞歸程序。
    改寫后的非遞歸算法與原來的遞歸算法相比,結(jié)構(gòu)不夠清晰,可讀性較差,有的還需要經(jīng)過一系列優(yōu)化。
  • 借助棧改寫遞歸的方法(了解)
    (1)設(shè)置一個(gè)工作棧存放遞歸工作記錄(包括實(shí)參、返回地址及局部變量等)。
    (2)進(jìn)入非遞歸調(diào)用入口(即被調(diào)用程序開始處)將調(diào)用程序傳來的實(shí)參和返回地址入棧(遞歸程序不可以作為主程序,因而可認(rèn)為初始是被某個(gè)調(diào)用程序調(diào)用)。
    (3)進(jìn)入遞歸調(diào)用入口:當(dāng)不滿足遞歸結(jié)束條件時(shí),逐層遞歸,將實(shí)參、返回地址及局部變量入棧,這一過程可用循環(huán)語句來實(shí)現(xiàn)——模擬遞歸分解的過程。
    (4)遞歸結(jié)束條件滿足,將到達(dá)遞歸出口的給定常數(shù)作為當(dāng)前的函數(shù)值。
    (5)返回處理:在棧不空的情況下,反復(fù)退出棧頂記錄,根據(jù)記錄中的返回地址進(jìn)行題意規(guī)定的操作,即逐層計(jì)算當(dāng)前函數(shù)值,直至??諡橹埂M遞歸求值過程。

四、隊(duì)列的C語言表示和實(shí)現(xiàn)

隊(duì)列的表示

  • 建立順序隊(duì)列結(jié)構(gòu)為其靜態(tài)分配或動(dòng)態(tài)申請(qǐng)一片連續(xù)的存儲(chǔ)空間,并設(shè)置兩個(gè)指針進(jìn)行管理。一個(gè)是隊(duì)頭指針front,它指向隊(duì)頭元素;另一個(gè)是隊(duì)尾指針rear,它指向下一個(gè)入隊(duì)元素的存儲(chǔ)位置(見下述隊(duì)列標(biāo)志問題)。
  • 在隊(duì)尾插入一個(gè)元素,rear++;在隊(duì)頭刪除一個(gè)元素,front++。當(dāng)front = rear時(shí),隊(duì)列中沒有任何元素,稱為空隊(duì)列。
  • 假上溢現(xiàn)象:
    當(dāng)rear = MAXSIZE時(shí),隊(duì)列發(fā)生上溢。此時(shí)若front = 0,為“真上溢”;但若front\neq0時(shí),為“假上溢”。
    “假上溢”:由于入隊(duì)和出隊(duì)操作中,頭尾指針只增加不減小,致使被刪元素的空間無法重新利用,如圖1所示。當(dāng)隊(duì)列中實(shí)際的元素個(gè)數(shù)遠(yuǎn)遠(yuǎn)小于向量空間的規(guī)模時(shí),也可能由于尾指針已超越向量空間的上界而不能做入隊(duì)操作。
    圖1
  • 解決假上溢的方法:
    1.將隊(duì)中元素依次向頭方向移動(dòng)。缺點(diǎn):浪費(fèi)時(shí)間,每移動(dòng)一次,隊(duì)中元素都要移動(dòng)。
    2.將隊(duì)空間設(shè)想成一個(gè)循環(huán)的表,即分配給隊(duì)列的m個(gè)存儲(chǔ)單元可以循環(huán)使用,當(dāng)rear為MAXSIZE時(shí),若向量的開始端空著,又可從頭使用空著的空間,當(dāng)front為MAXSIZE時(shí),也是一樣。
    • 引入循環(huán)隊(duì)列:實(shí)現(xiàn)方法:模運(yùn)算%
  • 隊(duì)列標(biāo)志問題:
    隊(duì)空:front == rear,隊(duì)滿:front == rear
    解決方法:
    1.另外設(shè)一個(gè)標(biāo)志區(qū)別隊(duì)空,隊(duì)滿。
    2.另設(shè)變量,記錄元素個(gè)數(shù)。
    3.少用一個(gè)元素空間(常用方法)。
    利用方法3解決,故隊(duì)尾指針rear指向下一個(gè)入隊(duì)元素的存儲(chǔ)位置,而不直接指向隊(duì)尾。隊(duì)空:front == rear,隊(duì)滿:(rear+1)%MAXSIZE == front

順序隊(duì)列的實(shí)現(xiàn)

//數(shù)據(jù)結(jié)構(gòu)與算法分析-隊(duì)列-順序?qū)崿F(xiàn)
#include<stdio.h>
#include<stdlib.h>

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1  //不可實(shí)現(xiàn)
#define OVERFLOW -2  //溢出

#define MAXSIZE 100  //長(zhǎng)度

typedef int value;  //返回值類型
typedef int status;  //返回狀態(tài)類型
typedef int elemtype;  //元素類型

typedef struct
{
    elemtype *base;  //初始化的動(dòng)態(tài)分配空間
    int front;  //"頭指針"
    int rear;  //"尾指針"
}SqQueue;

status initqueue(SqQueue *Q);  //順序隊(duì)列初始化
value queuelength(SqQueue Q);  //返回順序隊(duì)列長(zhǎng)度
status enqueue(SqQueue *Q,elemtype e);  //入隊(duì)
status dequeue(SqQueue *Q,elemtype *e);  //出隊(duì)
elemtype gethead(SqQueue Q);  //返回隊(duì)頭元素

int main()
{
    printf("\n測(cè)試\n");
//  system("pause");
    return 0;
}
status initqueue(SqQueue *Q)
{
    Q->base = (elemtype*)malloc(MAXSIZE*sizeof(elemtype));
    if(!Q->base)
        exit(OVERFLOW);
    Q->front = 0;
    Q->rear = 0;
    return OK;
}
value queuelength(SqQueue Q)
{
    return ((Q.rear-Q.front+MAXSIZE)%MAXSIZE);
}
status enqueue(SqQueue *Q,elemtype e)
{
    if((Q->rear+1)%MAXSIZE == Q->front)
        return ERROR;
    Q->base[Q->rear] = e;
    Q->rear = (Q->rear+1)%MAXSIZE;
    return OK;
}
status dequeue(SqQueue *Q,elemtype *e)
{
    if(Q->front == Q->rear)
        return ERROR;
    *e = Q->base[Q->front];
    Q->front = (Q->front+1)%MAXSIZE;
    return OK;
}
elemtype gethead(SqQueue Q)
{
    if(Q.front!=Q.rear)
        return Q.base[Q.front];
}

鏈?zhǔn)疥?duì)列的實(shí)現(xiàn)

//數(shù)據(jù)結(jié)構(gòu)與算法分析-隊(duì)列-鏈?zhǔn)綄?shí)現(xiàn)
#include<stdio.h>
#include<stdlib.h>

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1  //不可實(shí)現(xiàn)
#define OVERFLOW -2  //溢出

#define MAXSIZE 100  //長(zhǎng)度

typedef int value;  //返回值類型
typedef int status;  //返回狀態(tài)類型
typedef int elemtype;  //元素類型

typedef struct Qnode
{
    elemtype data;
    struct Qnode *next;
}Qnode,*QueuePtr;
typedef struct
{
    QueuePtr front;
    QueuePtr rear;
}LinkQueue;

status initqueue(LinkQueue *Q);  //鏈?zhǔn)疥?duì)列初始化
status destroyqueue(LinkQueue *Q);  //銷毀鏈?zhǔn)疥?duì)列
status enqueue(LinkQueue *Q,elemtype e);  //入隊(duì)
status dequeue(LinkQueue *Q,elemtype *e);  //出隊(duì)
status gethead(LinkQueue Q,elemtype *e);  //返回隊(duì)頭元素

int main()
{
    printf("\n測(cè)試\n");
//  system("pause");
    return 0;
}
status initqueue(LinkQueue *Q)
{
    Q->rear = (QueuePtr)malloc(sizeof(Qnode));
    Q->front = Q->rear;
    if(!Q->front)
        exit(OVERFLOW);
    Q->front->next = NULL;
    return OK;
}
status destroyqueue(LinkQueue *Q)
{
    Qnode *p;
    while(Q->front)
    {
        p = Q->front->next;
        free(Q->front);
        Q->front = p;
    }
    return OK;
}
status enqueue(LinkQueue *Q,elemtype e)
{
    Qnode *p = (QueuePtr)malloc(sizeof(Qnode));
    if(!p)
        exit(OVERFLOW);
    p->data = e;
    p->next = NULL;
    Q->rear->next = p;
    Q->rear = p;
    return OK;
}
status dequeue(LinkQueue *Q,elemtype *e)
{
    if(Q->front == Q->rear)
        return ERROR;
    Qnode *p;
    p = Q->front->next;
    *e = p->data;
    Q->front->next = p->next;
    if(Q->rear == p)
        Q->rear = Q->front;
    free(p);
    return OK;
}
status gethead(LinkQueue Q,elemtype *e)
{
    if(Q.front == Q.rear)
        return ERROR;
    *e = Q.front->next->data;
    return OK;
}

參考文獻(xiàn):

  1. https://www.bilibili.com/video/BV1nJ411V7bd?p=62
  2. https://baike.baidu.com/item/%E9%98%9F%E5%88%97/14580481?fr=aladdin

:永遠(yuǎn)不要忘記提升自己~~
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容