數據結構中的棧與隊列:原理、實現與應用

前言:棧和隊列是計算機科學中兩種最基礎的線性數據結構,它們的獨特操作規則和廣泛的應用場景使其成為每一位開發者必須掌握的核心知識。本文將通過生活案例、代碼實現和實際應用場景,帶您深入理解這兩種數據結構的精髓。

1.棧(Stack)

基本定義

棧是一種受限的線性表,僅允許在同一端(棧頂)進行數據插入(push)和刪除(pop)操作。其核心特性遵循LIFO(后進先出)(Last In First Out)原則,即后進入的元素優先被訪問。

LIFO原則

  • 后進先出(Last In First Out):最后入棧的元素總是最先出棧

  • 入棧(Push):將新元素放入棧頂

  • 出棧(Pop):移除并返回棧頂元素

核心機制
  • 單端操作:所有操作集中在棧頂完成

  • 動態指針:通過棧頂指針(top)實時跟蹤最新元素位置

  • 操作限制禁止直接訪問中間元素,必須按序操作

  • 空間管理:順序棧需預判容量,鏈式棧動態擴展但需額外指針空間

2.棧的實現

實現方式優點缺點適用場景
動態數組緩存友好,訪問速度快擴容時需要拷貝數據通用場景
鏈表無需預分配空間每個元素需要額外指針空間元素數量變化劇烈
靜態數組
內存分配確定容量固定,不夠靈活嵌入式系統/內存受限環境

本文將以動態數組為基礎,手把手帶你用C語言實現一個智能的“自動擴容棧”。

/* 棧元素類型定義(方便修改數據類型) */
typedef int STDataType;/* 棧結構體定義arr: 動態數組首地址top: 棧頂指針(當前元素數量)capacity: 數組總容量 */
typedef struct Stack {STDataType* arr;int top;        int capacity;   
} ST;/* 功能:初始化棧結構參數:ps - 指向棧的指針關鍵點:初始狀態數組為空,容量為0 */
void STInit(ST* ps) {assert(ps);ps->arr = NULL;ps->capacity = ps->top = 0;
}/* 功能:壓入元素到棧頂參數:ps - 棧指針,x - 要入棧的元素關鍵點:自動擴容策略(4→8→16...)示例:初始容量0時首次push會擴容到4 */
void STPush(ST* ps, STDataType x) {assert(ps);// 容量檢查與擴容if (ps->capacity == ps->top) {int newcapacity = ps->capacity ? 2*ps->capacity : 4;STDataType* temp = realloc(ps->arr, newcapacity*sizeof(STDataType));if (!temp) { perror("malloc"); exit(1); }ps->arr = temp;ps->capacity = newcapacity;}ps->arr[ps->top++] = x; // 先存數據再移動指針
}/* 功能:判斷棧是否為空參數:ps - 棧指針返回:true表示空棧,false非空示例:初始化后返回true,push后返回false */
bool STEmpty(ST* ps) {assert(ps);return ps->top == 0;
}/* 功能:彈出棧頂元素參數:ps - 棧指針關鍵點:實際只移動指針,不刪除數據注意:空棧彈出會導致斷言失敗 */
void STPop(ST* ps) {assert(ps && !STEmpty(ps));ps->top--; // 邏輯刪除
}/* 功能:獲取棧元素數量參數:ps - 棧指針返回:當前元素個數示例:push三次后返回3 */
int STSize(ST* ps) {assert(ps);return ps->top; // top直接表示數量
}/* 功能:查看棧頂元素(不彈出)參數:ps - 棧指針返回:棧頂元素值關鍵點:top-1才是最后存入的位置示例:棧內[10,20]時返回20 */
STDataType STTop(ST* ps) {assert(ps && !STEmpty(ps));return ps->arr[ps->top-1];
}/* 功能:銷毀棧并釋放內存參數:ps - 棧指針關鍵點:必須調用防止內存泄漏注意:調用后棧不可再使用 */
void STDestroy(ST* ps) {assert(ps);if (ps->arr) free(ps->arr);ps->arr = NULL;ps->capacity = ps->top = 0;
}

測試用例?

int main()
{ST st;          // 聲明棧變量(未初始化狀態)STInit(&st);    // 初始化棧 → arr=NULL, capacity=0, top=0STPush(&st, 1);  // 觸發擴容(0→4)→ arr[0]=1, top=1printf("%d\n", STSize(&st)); // 輸出1(當前元素數量)STPush(&st, 2);  // arr[1]=2, top=2printf("%d\n", STSize(&st)); // 輸出2STPush(&st, 3);  // arr[2]=3, top=3printf("%d\n", STSize(&st)); // 輸出3STPush(&st, 4);  // arr[3]=4, top=4(棧滿)printf("%d\n", STSize(&st)); // 輸出4while (!STEmpty(&st)) //打印棧中所有元素{          printf("%d ", STTop(&st));  // 從棧頂開始輸出:4 3 2 1STPop(&st);           // 每次循環top減1}printf("\n%d", STSize(&st)); // 輸出0(此時棧空)STDestroy(&st);          // 必須調用!釋放動態內存return 0;
}

3.隊列(Queue)

基本定義

隊列是另一種受限線性表,遵循FIFO(First In First Out)原則。元素從隊尾(rear)插入(enqueue),從隊首(front)移除,保持嚴格的先進先出順序。

核心機制
  • 雙指針系統:通過?front?rear 指針分別管理兩端

  • 循環優化:使用模運算實現環形緩沖區解決"假溢出"問題

  • 等待特性:元素按到達順序被處理,具有公平性特征

  • 容量管理:動態隊列可擴展,但需考慮內存碎片問題

4.隊列的實現

實現方式優點缺點適用場景
普通數組隊列實現簡單出隊效率低(需要搬移元素)教學演示
循環數組隊列高效利用內存需處理隊空/隊滿邊界條件固定容量生產消費場景
鏈表隊列動態擴容靈活內存碎片化,緩存不友好頻繁擴容/元素大小不一
動態數組隊列平衡性能與靈活性擴容時產生瞬時延遲通用場景

在本文中,會著重介紹下面三種隊列,普通數組隊列的使用并不常見,我們在這里并不過多介紹,大家可以自己嘗試著實現。首先,我們實現鏈式隊列。循環數組隊列和動態數組隊列我們作為后面習題補充會涉及到。

注意:鏈式隊列的實現與單鏈表的實現大差不差,前面單鏈表的實現非常重要,能夠完成單鏈表的實現代碼,實現鏈式隊列代碼就不成問題。

typedef int QDataType;  // 隊列元素類型別名,方便修改存儲類型// 隊列節點結構(鏈式存儲)
typedef struct QueueNode {int val;              // 存儲數據struct QueueNode* next; // 指向下一個節點
} QNode;// 隊列管理結構
typedef struct Queue {QNode* phead;  // 隊頭指針(刪除端)QNode* ptail;  // 隊尾指針(插入端)int size;       // 當前元素數量
} Queue;// 功能:初始化隊列結構
// 參數:pq - 指向隊列的指針
// 關鍵點:將指針置空,size清零
void QueueInit(Queue* pq) {assert(pq);  // 防御性編程,確保指針有效pq->phead = pq->ptail = NULL;pq->size = 0;  // 初始為空隊列
}// 功能:創建新節點
// 參數:x - 要存儲的數據
// 返回:新節點指針
// 關鍵點:內存分配與初始化
QNode* Createnode(QDataType x) {QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL) {          // 內存不足處理perror("malloc");           // 打印錯誤信息exit(1);                    // 直接終止程序}newnode->val = x;               // 存儲數據newnode->next = NULL;           // 初始化指針return newnode;
}// 功能:在隊尾插入新元素
// 參數:pq - 隊列指針,x - 要插入的數據
// 關鍵點:維護頭尾指針關系
void QueuePush(Queue* pq, QDataType x) {assert(pq);QNode* newnode = Createnode(x);  // 創建新節點if (pq->phead == NULL) {        // 空隊列情況pq->phead = pq->ptail = newnode;} else {                        // 非空隊列pq->ptail->next = newnode;  // 鏈接新節點pq->ptail = newnode;        // 更新尾指針}pq->size++;  // 元素計數增加
}// 功能:判斷隊列是否為空
// 參數:pq - 隊列指針
// 返回:true為空,false非空
// 關鍵點:只需檢查頭指針
bool QueueEmpty(Queue* pq) {assert(pq);return pq->phead == NULL;  // 頭指針為空即隊列空
}// 功能:刪除隊頭元素
// 參數:pq - 隊列指針
// 關鍵點:處理最后一個節點的特殊情況
void QueuePop(Queue* pq) {assert(pq);assert(!QueueEmpty(pq));  // 確保隊列非空QNode* del = pq->phead;     // 保存待刪除節點pq->phead = pq->phead->next;// 頭指針后移// 處理刪除最后一個元素的情況if (pq->phead == NULL) {pq->ptail = NULL;      // 尾指針也必須置空}free(del);      // 釋放節點內存pq->size--;     // 元素計數減少
}// 功能:查看隊頭元素(不刪除)
// 參數:pq - 隊列指針
// 返回:隊頭元素值
// 注意:隊列為空時觸發斷言
QDataType QueueFront(Queue* pq) {assert(pq);assert(!QueueEmpty(pq));  // 防御空隊列訪問return pq->phead->val;    // 直接返回頭節點值
}// 功能:查看隊尾元素(不刪除)
// 參數:pq - 隊列指針
// 返回:隊尾元素值
QDataType QueueBack(Queue* pq) {assert(pq);assert(!QueueEmpty(pq));  // 防御空隊列訪問return pq->ptail->val;    // 直接返回尾節點值
}// 功能:獲取當前元素數量
// 參數:pq - 隊列指針
// 返回:隊列元素個數
// 優勢:O(1)時間復雜度
int QueueSize(Queue* pq) {assert(pq);return pq->size;  // 直接返回計數器值
}// 功能:釋放隊列所有內存
// 參數:pq - 隊列指針
// 關鍵點:必須遍歷釋放所有節點
void QueueDestroy(Queue* pq) {assert(pq);QNode* curr = pq->phead;while (curr) {QNode* del = curr;   // 保存當前節點curr = curr->next;   // 移動到下一個節點free(del);           // 釋放當前節點}pq->phead = pq->ptail = NULL;  // 重置指針pq->size = 0;                  // 重置計數器
}

測試用例

int main() {Queue q;QueueInit(&q);  // 必須初始化QueuePush(&q, 10);QueuePush(&q, 20);printf("隊頭:%d\n", QueueFront(&q));  // 輸出10QueuePop(&q);  // 刪除10printf("當前大小:%d\n", QueueSize(&q));  // 輸出1QueueDestroy(&q);  // 必須銷毀return 0;
}

?5.棧與隊列算法題

5.1?力扣:有效的括號

?1. 核心思想

  • 棧的LIFO特性:利用棧后進先出的特性,確保最近打開的括號必須最先閉合

  • 匹配原則:遍歷字符串時,遇到左括號入棧,遇到右括號必須與棧頂左括號類型匹配

2. 執行流程

  1. 初始化棧:創建空棧用于存儲待匹配的左括號

  2. 遍歷字符:逐個處理輸入字符串的每個字符

    • 左括號處理(/[/{?→ 壓入棧頂

    • 右括號處理

      • 檢查棧空 → 棧空直接返回false

      • 棧非空 → 檢查棧頂是否匹配 → 匹配則彈出,不匹配返回false

  3. 最終校驗:遍歷完成后檢查棧是否為空(所有左括號均已匹配)

//代碼中所用函數都是上文棧的實現中的函數
bool isValid(char* s) {ST st;STInit(&st);while(*s != '\0'){if(*s == '(' || *s == '[' || *s == '{'){STPush(&st,*s);}else{if(STEmpty(&st))return false;STDataType ch1 = STTop(&st);if((ch1 == '(' && *s == ')')|| (ch1 == '[' && *s == ']')|| (ch1 == '{' && *s == '}'))STPop(&st);else{STDestroy(&st);return false;}}s++;}if(!STEmpty(&st))return false;STDestroy(&st);return true;
}

5.2力扣:用隊列實現棧?

// 代碼中所用函數都是上文隊列的實現中的函數// 使用兩個隊列實現棧的結構定義
typedef struct {Queue q1;Queue q2;
} MyStack;// 創建棧實例并初始化兩個隊列
MyStack* myStackCreate() 
{MyStack* pst = (MyStack*)malloc(sizeof(MyStack));QueueInit(&pst->q1);QueueInit(&pst->q2);return pst;
}// 入棧操作:將元素壓入非空隊列(若都為空則選擇q1)
void myStackPush(MyStack* obj, int x) {if(!QueueEmpty(&obj->q1))QueuePush(&obj->q1, x);elseQueuePush(&obj->q2, x);
}// 出棧操作:將非空隊列的前n-1個元素轉移到空隊列,彈出最后一個元素
int myStackPop(MyStack* obj) {Queue* emptyQue = &obj->q1;Queue* nonEmptyQue = &obj->q2;// 確定空隊列和非空隊列if(QueueEmpty(nonEmptyQue)) {emptyQue = &obj->q2;nonEmptyQue = &obj->q1;}// 將非空隊列的前n-1個元素轉移到空隊列while(QueueSize(nonEmptyQue) > 1) {QDataType data = QueueFront(nonEmptyQue);QueuePop(nonEmptyQue);QueuePush(emptyQue, data);}// 彈出并返回最后一個元素QDataType ret = QueueFront(nonEmptyQue);QueuePop(nonEmptyQue);return ret;
}// 獲取棧頂元素:直接返回非空隊列的隊尾元素
int myStackTop(MyStack* obj) {if(!QueueEmpty(&obj->q1))return QueueBack(&obj->q1);elsereturn QueueBack(&obj->q2);
}// 判斷棧是否為空:當兩個隊列都為空時棧為空
bool myStackEmpty(MyStack* obj) {return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}// 釋放棧內存:銷毀兩個隊列并釋放棧結構
void myStackFree(MyStack* obj) {QueueDestroy(&obj->q1);QueueDestroy(&obj->q2);free(obj);obj = NULL;
}

?5.3力扣:用棧實現隊列

?

// 代碼中所用函數都是上文棧的實現中的函數// 使用兩個棧實現隊列的結構定義
typedef struct {ST Pushst;    // 用于入隊操作的棧ST Popst;     // 用于出隊操作的棧
} MyQueue;// 創建隊列實例并初始化兩個棧
MyQueue* myQueueCreate() {MyQueue* pst = (MyQueue*)malloc(sizeof(MyQueue));STInit(&pst->Pushst);STInit(&pst->Popst);return pst;
}// 入隊操作:直接壓入Push棧
void myQueuePush(MyQueue* obj, int x) {STPush(&obj->Pushst, x);
}// 出隊操作:若Pop棧為空,則將Push棧元素全部倒入Pop棧,再彈出Pop棧頂元素
int myQueuePop(MyQueue* obj) {if(STEmpty(&obj->Popst)) {// 將Push棧的元素逆序倒入Pop棧while(!STEmpty(&obj->Pushst)) {STDataType data = STTop(&obj->Pushst);STPop(&obj->Pushst);STPush(&obj->Popst, data);}}STDataType ret = STTop(&obj->Popst);STPop(&obj->Popst);return ret;
}// 獲取隊首元素:邏輯同出隊,但不彈出元素
int myQueuePeek(MyQueue* obj) {if(STEmpty(&obj->Popst)) {while(!STEmpty(&obj->Pushst)) {STDataType data = STTop(&obj->Pushst);STPop(&obj->Pushst);STPush(&obj->Popst, data);}}return STTop(&obj->Popst);
}// 判斷隊列是否為空:當兩個棧都為空時隊列為空
bool myQueueEmpty(MyQueue* obj) {return STEmpty(&obj->Popst) && STEmpty(&obj->Pushst);
}// 釋放隊列內存:銷毀兩個棧并釋放隊列結構
void myQueueFree(MyQueue* obj) {STDestroy(&obj->Popst);STDestroy(&obj->Pushst);free(obj);obj = NULL;
}

?5.4力扣:設計循環隊列

// 使用數組實現的環形隊列結構
typedef struct {int* arr;        // 存儲隊列元素的數組int front;       // 隊頭指針:指向隊列第一個有效元素int rear;        // 隊尾指針:指向隊列最后一個元素的下一個位置int capacity;    // 隊列的最大容量(實際存儲元素個數為capacity)
} MyCircularQueue;// 創建環形隊列實例,k為隊列容量
MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));// 分配k+1大小的數組,浪費一個空間用于區分隊列滿和空的狀態obj->arr = (int*)malloc(sizeof(int) * (k + 1));obj->front = obj->rear = 0;    // 初始化隊頭隊尾指針obj->capacity = k;             // 設置隊列容量return obj;
}// 判斷隊列是否為空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {// 當隊頭和隊尾指針指向同一位置時,隊列為空return obj->rear == obj->front;
}// 判斷隊列是否已滿
bool myCircularQueueIsFull(MyCircularQueue* obj) {// 當隊尾指針的下一個位置是隊頭指針時,隊列已滿// 使用取模運算實現環形效果return (obj->rear + 1) % (obj->capacity + 1) == obj->front;
}// 入隊操作
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {if (myCircularQueueIsFull(obj))return false;    // 隊列已滿,入隊失敗obj->arr[obj->rear] = value;    // 將元素放入隊尾位置obj->rear = (obj->rear + 1) % (obj->capacity + 1);    // 更新隊尾指針,循環前進return true;
}// 出隊操作
bool myCircularQueueDeQueue(MyCircularQueue* obj) {if (myCircularQueueIsEmpty(obj))return false;    // 隊列為空,出隊失敗obj->front = (obj->front + 1) % (obj->capacity + 1);    // 更新隊頭指針,循環前進return true;
}// 獲取隊頭元素
int myCircularQueueFront(MyCircularQueue* obj) {if (myCircularQueueIsEmpty(obj))return -1;    // 隊列為空,返回-1表示無效值return obj->arr[obj->front];    // 返回隊頭指針指向的元素
}// 獲取隊尾元素
int myCircularQueueRear(MyCircularQueue* obj) {if (myCircularQueueIsEmpty(obj))return -1;    // 隊列為空,返回-1表示無效值// 計算隊尾元素的實際位置(隊尾指針前一個位置)int prev = (obj->rear - 1 + (obj->capacity + 1)) % (obj->capacity + 1);return obj->arr[prev];
}// 釋放隊列內存
void myCircularQueueFree(MyCircularQueue* obj) {free(obj->arr);    // 釋放存儲元素的數組free(obj);         // 釋放隊列結構體obj = NULL;        // 防止野指針
}
  1. 數組大小

    • 實際分配大小為?capacity + 1浪費一個空間用于區分隊列滿和隊列空的狀態
    • 隊列滿條件:(rear + 1) % (capacity + 1) == front
    • 隊列空條件:rear == front
  2. 指針移動

    • 隊頭指針front:指向隊列的第一個有效元素
    • 隊尾指針rear:指向隊列最后一個元素的下一個位置
    • 使用% (capacity + 1)實現環形效果
  3. 邊界處理

    • 入隊時直接在rear位置賦值,然后rear指針后移
    • 出隊時直接將front指針后移,無需真正刪除元素
    • 獲取隊尾元素時需要計算rear的前一個位置,處理rear為 0 的情況

5.5設計動態循環列表

#include <stdlib.h>
#include <assert.h>typedef struct {int* data;       // 存儲隊列元素的動態數組int front;       // 隊頭指針,指向隊列第一個元素int rear;        // 隊尾指針,指向隊列最后一個元素的下一個位置int capacity;    // 當前隊列容量int size;        // 當前隊列元素個數
} DynamicQueue;// 創建動態隊列,初始容量為initialCapacity
DynamicQueue* createQueue(int initialCapacity) {DynamicQueue* queue = (DynamicQueue*)malloc(sizeof(DynamicQueue));assert(queue != NULL);queue->data = (int*)malloc(sizeof(int) * initialCapacity);assert(queue->data != NULL);queue->front = 0;queue->rear = 0;queue->size = 0;queue->capacity = initialCapacity;return queue;
}// 判斷隊列是否為空
bool isEmpty(DynamicQueue* queue) {return queue->size == 0;
}// 判斷隊列是否已滿(實際不會滿,會自動擴容)
bool isFull(DynamicQueue* queue) {return queue->size == queue->capacity;
}// 擴容隊列,新容量為原容量的2倍
void resizeQueue(DynamicQueue* queue) {int newCapacity = queue->capacity * 2;int* newData = (int*)malloc(sizeof(int) * newCapacity);assert(newData != NULL);// 復制原隊列元素到新數組for (int i = 0; i < queue->size; i++) {newData[i] = queue->data[(queue->front + i) % queue->capacity];}free(queue->data);queue->data = newData;queue->front = 0;queue->rear = queue->size;queue->capacity = newCapacity;
}// 入隊操作
void enqueue(DynamicQueue* queue, int value) {if (isFull(queue)) {resizeQueue(queue);}queue->data[queue->rear] = value;queue->rear = (queue->rear + 1) % queue->capacity;queue->size++;
}// 出隊操作,返回隊頭元素
int dequeue(DynamicQueue* queue) {assert(!isEmpty(queue));int value = queue->data[queue->front];queue->front = (queue->front + 1) % queue->capacity;queue->size--;return value;
}// 獲取隊頭元素
int getFront(DynamicQueue* queue) {assert(!isEmpty(queue));return queue->data[queue->front];
}// 獲取隊列大小
int getSize(DynamicQueue* queue) {return queue->size;
}// 釋放隊列內存
void freeQueue(DynamicQueue* queue) {free(queue->data);free(queue);
}

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/80474.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/80474.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/80474.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

如何選擇自己喜歡的cms

選擇內容管理系統cms what is cms1.whatcms.org2.IsItWP.com4.Wappalyzer5.https://builtwith.com/6.https://w3techs.com/7. https://www.netcraft.com/8.onewebtool.com如何在不使用 CMS 檢測器的情況下手動檢測 CMS 結論 在開始構建自己的數字足跡之前&#xff0c;大多數人會…

SDC命令詳解:使用all_outputs命令進行查詢

相關閱讀 SDC命令詳解https://blog.csdn.net/weixin_45791458/category_12931432.html all_outputs命令用于創建一個輸出端口對象集合&#xff0c;關于設計對象和集合的更詳細介紹&#xff0c;可以參考下面的博客。 Synopsys&#xff1a;設計對象https://chenzhang.blog.csdn…

vue 中的ref

vue 中的ref vue 中的ref 1. ??ref?? ** 的基本作用** 在 Vue 中&#xff0c;ref 是用來獲取 DOM 元素或者組件實例的一種方式。對于 <el-form> 組件&#xff0c;通過 ref 可以獲取到該表單組件的實例&#xff0c;進而調用表單組件提供的各種方法和訪問其屬性。 …

數據庫版本控制工具--flyway

一. 什么是Flyway Flyway 是一款開源的數據庫遷移工具。它采用簡單直觀的方式管理數據庫變更&#xff0c;通過版本化的遷移腳本確保數據庫結構的一致性和可重復性。無論是開發環境、測試環境還是生產環境&#xff0c;Flyway 都能確保數據庫變更按照預期順序執行&#xff0c;避…

C++使用PoDoFo庫處理PDF文件

&#x1f4da; PoDoFo 簡介 PoDoFo 是一個用 C 編寫的自由開源庫&#xff0c;專用于 讀取、寫入和操作 PDF 文件。它適用于需要程序化處理 PDF 文件的應用程序&#xff0c;比如批量生成、修改、合并、提取元數據、繪圖等。 &#x1f31f; 核心特點 特性說明&#x1f4c4; P…

論文分享? arXiv2025 | TTRL: Test-Time Reinforcement Learning

TTRL: Test-Time Reinforcement Learning TTRL&#xff1a;測試時強化學習 https://github.com/PRIME-RL/TTRL &#x1f4d6;導讀&#xff1a;本篇博客有&#x1f9a5;精讀版、&#x1f407;速讀版及&#x1f914;思考三部分&#xff1b;精讀版是全文的翻譯&#xff0c;篇幅較…

dify插件接入fastmcp示例

文章目錄 1. 使用python完成mcp服務1.1 準備環境&#xff08;python安裝fastmcp&#xff09;1.2 mcp服務端示例代碼1.3 啟動mcp服務端 2. dify接入2.1 安裝MCP SSE和 Agent 策略&#xff08;支持 MCP 工具&#xff09; 插件2.2 dify agent插件配置mcp:2.3 mcp服務配置&#xff…

Linux 挖礦木馬排查命令清單

Linux 挖礦木馬排查命令清單 1. 系統資源使用情況檢查 # 查看CPU、內存使用情況 top -c# 檢查CPU占用最高的進程 ps aux --sort-%cpu# 查找可疑進程名 ps -ef | grep -i miner\|cpu\|GPU\|xmr# 檢查網絡連接情況 lsof -i2. 可疑進程和隱藏進程檢查 # 檢查僵尸進程 ps -ef | …

PyTorch 中如何針對 GPU 和 TPU 使用不同的處理方式

一個簡單的矩陣乘法例子來演示在 PyTorch 中如何針對 GPU 和 TPU 使用不同的處理方式。 這個例子會展示核心的區別在于如何獲取和指定計算設備&#xff0c;以及&#xff08;對于 TPU&#xff09;可能需要額外的庫和同步操作。 示例代碼&#xff1a; import torch import tim…

自主shell命令行解釋器

目標 能處理普通命令能處理內建命令 實現原理 用下面的時間軸來表示時間發生次序。時間從左向右。shell由標識為sh的方塊&#xff0c;它隨著時間從左向右移動。 shell從用戶讀入字符串“ls”。shell建立一個新的進程&#xff0c;然后等待進程中運行ls程序并等待進程結束。 …

如何在sheel中運行Spark

啟動hdfs集群&#xff0c;打開hadoop100:9870&#xff0c;在wcinput目錄下上傳一個包含很多個單詞的文本文件。 啟動之后在spark-shell中寫代碼。 // 讀取文件&#xff0c;得到RDD val rdd1 sc.textFile("hdfs://hadoop100:8020/wcinput/words.txt") // 將單詞進行切…

【入門】數字走向II

描述 輸入整數N&#xff0c;輸出相應方陣。 輸入描述 一個整數N。&#xff08; 0 < n < 10 ) 輸出描述 一個方陣&#xff0c;每個數字的場寬為3。 #include <bits/stdc.h> using namespace std; int main() {int n;cin>>n;for(int in;i>1;i--){for(…

Python自動化-python基礎(下)

六、帶參數的裝飾器 七、函數生成器 運行結果&#xff1a; 八、通過反射操作對象方法 1.添加和覆蓋對象方法 2.刪除對象方法 通過使用內建函數: delattr() # 刪除 x.a() print("通過反射刪除之后") delattr(x, "a") x.a()3 通過反射判斷對象是否有指定…

重新定義高性能:Hyperlane —— Rust生態中的極速HTTP服務器

重新定義高性能&#xff1a;Hyperlane —— Rust生態中的極速HTTP服務器 &#x1f680; 為什么選擇Hyperlane&#xff1f; 在追求極致性能的Web服務開發領域&#xff0c;Hyperlane 憑借其獨特的Rust基因和架構設計&#xff0c;在最新基準測試中展現出令人驚艷的表現&#xff…

通俗的理解MFC消息機制

1. 消息是什么&#xff1f; 想象你家的門鈴響了&#xff08;比如有人按門鈴、敲門、或者有快遞&#xff09;&#xff0c;這些都是“消息”。 在 MFC 中&#xff0c;消息就是系統或用戶觸發的各種事件&#xff0c;比如鼠標點擊&#xff08;WM_LBUTTONDOWN&#xff09;、鍵盤輸入…

騰訊開源SuperSonic:AI+BI如何重塑制造業數據分析?

目錄 一、四款主流ChatBI產品 二、ChatBI應用案例與實際落地情況 三、SuperSonic底層原理 3.1、Headless?BI 是什么 3.2、S2SQL?是什么 3.3、SuperSonic 平臺架構 四、ChatBI應用細節深挖 五、與現有系統的集成方案 六、部署和安全 七、開源生態、可擴展性與二次開…

AI生成視頻推薦

以下是一些好用的 AI 生成視頻工具&#xff1a; 國內工具 可靈 &#xff1a;支持文本生成視頻、圖片生成視頻&#xff0c;適用于廣告、電影剪輯和短視頻制作&#xff0c;能在 30 秒內生成 6 秒的高清視頻&#xff08;1440p&#xff09;&#xff0c;目前處于免費測試階段。 即…

OrangePi Zero 3學習筆記(Android篇)5 - usbutils編譯(更新lsusb)

目錄 1. Ubuntu中編譯 2. AOSP編譯 3. 去掉原來的配置 3. 打包 4. 驗證lsusb 在Ubuntu中&#xff0c;lsusb的源代碼源自usbutils。而OrangePi Zero 3中lsusb的位置可以看文件H618-Android12-Src/external/toybox/Android.bp&#xff0c; "toys/other/lsusb.c",…

bcm5482 phy 場景總結

1,BCM5482是一款雙端口10/100/1000BASE-T以太網PHY芯片,支持多種速率和雙工模式。其配置主要通過MDIO(Management Data Input/Output)接口進行,MDIO接口用于訪問PHY芯片內部的寄存器,從而配置網絡速率、雙工模式以及其他相關參數。 a,具體以下面兩種場景舉例 2. 寄存器和…

RedHat磁盤的添加和擴容

前情提要 &#x1f9f1; 磁盤結構流程概念圖&#xff1a; 物理磁盤 (/dev/sdX) └── 分區&#xff08;如 /dev/sdX1&#xff09;或整塊磁盤&#xff08;直接使用&#xff09; └── 物理卷 (PV, 用 pvcreate) └── 卷組 (VG, 用 vgcreate) …