數據結構--鏈表的基本操作

1. 鏈表的概念及結構

概念:鏈表是?種物理存儲結構上?連續、?順序的存儲結構,數據元素的邏輯順序是通過鏈表 中的指針鏈接次序實現的 。

鏈表也是線性表的一種。

鏈表的結構跟???廂相似,淡季時?次的?廂會相應減少,旺季時?次的?廂會額外增加?節。只 需要將???的某節?廂去掉/加上,不會影響其他?廂,每節?廂都是獨?存在的。

?廂是獨?存在的,且每節?廂都有??。想象?下這樣的場景,假設每節?廂的??都是鎖上的狀 態,需要不同的鑰匙才能解鎖,每次只能攜帶?把鑰匙的情況下如何從?頭?到?尾?

最簡單的做法:每節?廂?都放?把下?節?廂的鑰匙。?

在鏈表?,每節“?廂”是什么樣的呢?

與順序表不同的是,鏈表?的每節"?廂"都是獨?申請下來的空間,我們稱之為“結點/節點

節點的組成主要有兩個部分:當前節點要保存的數據和保存下?個節點的地址(指針變量)

圖中指針變量 plist保存的是第?個節點的地址,我們稱plist此時“指向”第?個節點,如果我們希 望plist“指向”第?個節點時,只需要修改plist保存的內容為0x0012FFA0。

為什么還需要指針變量來保存下?個節點的位置?

鏈表中每個節點都是獨?申請的(即需要插?數據時才去申請?塊節點的空間),我們需要通過指針變量來保存下?個節點位置才能從當前節點找到下?個節點。

結合前?學到的結構體知識,我們可以給出每個節點對應的結構體代碼:

假設當前保存的節點為整型:

struct SListNode
{int data; //節點數據struct SListNode* next; //指針變量?保存下?個節點的地址
};

當我們想要保存?個整型數據時,實際是向操作系統申請了?塊內存,這個內存不僅要保存整型數 據,也需要保存下?個節點的地址(當下?個節點為空時保存的地址為空)。 當我們想要從第?個節點?到最后?個節點時,只需要在前?個節點拿上下?個節點的地址(下?個 節點的鑰匙)就可以了。

給定的鏈表結構中,如何實現節點從頭到尾的打印?

思考:當我們想保存的數據類型為字符型、浮點型或者其他?定義的類型時,該如何修改?

補充說明:

1、鏈式機構在邏輯上是連續的,在物理結構上不?定連續

2、節點?般是從堆上申請的

3、從堆上申請來的空間,是按照?定策略分配出來的,每次申請的空間可能連續,可能不連續

2. 單鏈表的實現

我們和順序表一樣定義三個文件,一個頭文件我們取個名字叫SList.h,兩個源文件分別取名叫SList.ctext.c,我們的SList.c用來實現鏈表的方法,text.c用來測試。

我們把單鏈表的功能函數全部在頭文件里面聲明一下,以及我們結構體的定義,還有我們需要用到的頭文件都放在.h文件里面。

.h

#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>//定義節點的結構
typedef int SLTDataType;typedef struct SListNode
{SLTDataType date;//數據struct SListNode* next;//指向節點的地址}SLTNode;void SLTPrint(SLTNode* phead);//打印void SLTBuyBode(SLTNode** pphead, SLTDataType x);//尾插void SLPushFront(SLTNode** pphead, SLTDataType x);//頭插void SLTPopBack(SLTNode** pphead);//尾刪void SLTPopFront(SLTNode** pphead);//頭刪SLTNode* SLFind(SLTNode* phead, SLTDataType x);//查找void SLTnsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);//指定位置之前插入數據void SLTnesertAfter(SLTNode* pos, SLTDataType x);//指定位置之后插入數據void SLTErase(SLTNode** pphead, SLTNode* pos);//刪除pos節點void SLTEreaseAfter(SLTNode* pos);//刪除pos之后的節點void SListDesTroy(SLTNode** pphead);//銷毀鏈表

以上就是我們的聲明了,要注意我們的類型,我們這里用typedef?定義了一個int類型給它取了個名字叫SLTDataType,當我們需要改類型的時候直接把int改成我們想要的類型就行。


我們和順序表一樣先來實現尾插,我們插入數據的時候需要申請節點,所以我們先來實現申請節點的函數。

節點的申請

SList.c
SLTNode* SLBuyNode(SLTDataType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("malloc fail!");exit(1);}newnode->date = x;newnode->next = NULL;return newnode;
}

申請空間可能導致申請失敗所以我們需要判斷一下,x是我們節點里面的數據。

現在來實現尾插

//尾插
void SLTBuyBode(SLTNode** pphead, SLTDataType x)
{assert(pphead);//*pphead就是指向第一個節點的指針//空鏈表和非空鏈表SLTNode* newnode = SLBuyNode(x);if (*pphead == NULL){*pphead = newnode;}else{//找尾SLTNode* ptail = *pphead;while (ptail->next){ptail = ptail->next;}//ptail指向的就是尾節點ptail->next = newnode;}
}

如果我們傳過來一個NULL,我們可以對他解引用嗎?那肯定是不行的,所以我們加個斷言。

我們要插入數據那肯定是需要申請節點的,我們把需要插入的數據x傳過去,然后進行找尾找到后讓我們的尾節點的next指向我們的新節點。

這里我們創建了一個指針變量讓它進行找尾的操作,如果用我們的頭節點不斷往后最后會指向我們的尾節點。

尾插實現好了我們用測試文件來測試一下

text.c

打印怎么實現的我們上面已經說了。我把打印的代碼直接放這了(SList.c)

void SLTPrint(SLTNode* phead)
{SLTNode* pcur = phead;while (pcur){printf("%d->", pcur->date);pcur = pcur->next;}printf("NULL\n");
}

頭插的實現

//頭插
void SLPushFront(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newnode = SLBuyNode(x);newnode->next = *pphead;*pphead = newnode;
}

頭插的實現其實就是把我們申請好的節點讓它的next指向我們的頭節點。?

測試一下:


尾刪的實現


//尾刪
void SLTPopBack(SLTNode** pphead)
{assert(pphead && *pphead);//鏈表只有一個節點if ((*pphead)->next == NULL)//-->優先級*{free(*pphead);*pphead = NULL;}else{//鏈表有多個節點SLTNode* prev = *pphead; //尾節點的前一個節點SLTNode* ptail = *pphead;//尾節點while (ptail->next){prev = ptail;//尾節點的前一個節點ptail = ptail->next;}free(ptail);ptail = NULL;prev->next = NULL;//讓我的尾節點指向空指針}
}

既然我們要刪除節點那么節點不能為空,所以需要斷言一下。

當鏈表只有一個節點的時候我們直接把它釋放就行了。

有多個節點的時候我們需要用一個指針變量用來保存我們的前一個節點。?

測試一下:


頭刪的實現

//頭刪
void SLTPopFront(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* next = (*pphead)->next;free(*pphead);*pphead = next;
}

我們要把頭節點給釋放掉,所以我們先把頭節點的next指向下一個節點的地址給保存起來。

測試一下:


查找的實現

//查找
SLTNode* SLFind(SLTNode* phead, SLTDataType x)
{SLTNode* pcur = phead;while (pcur){if (pcur->date == x){return pcur;}pcur = pcur->next;}return  NULL;
}

如果找到了我們就直接返回找到的節點,沒找到返回NULL。

測試一下:


指定位置之前插入數據的實現


//指定位置之前插入數據
void SLTnsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{assert(pphead && *pphead);assert(pos);SLTNode* newnode = SLBuyNode(x);if (pos == *pphead){//如果pos等于我們的頭節點我們直接使用頭插SLPushFront(pphead, x);}else{SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}newnode->next = pos;prev->next = newnode;}
}

pos是我們指定的位置,所以不能為空我們斷言一下。

插入數據肯定是要申請節點的。

如果pos等于我們的頭節點那么我們直接調用頭插就可以了。

我們定義一個指針變量用來保存前一個節點,然后用我們申請好了的節點的next指向我們的pos,在用我們前一個節點的next指向我們申請好了的節點。

測試一下:


指定位置之后插入數據

//指定位置之后插入數據
void SLTnesertAfter(SLTNode* pos, SLTDataType x)
{assert(pos);SLTNode* newnode = SLBuyNode(x);newnode->next = pos->next;pos->next = newnode;
}

這里我們用不到頭節點,所以只有兩個參數,這里的pos是指定位置所以不能為空我們要加個斷言,這里直接用申請好的節點的next指向pos的下一個節點,然后再讓pos的next指向我們申請好的節點,這樣就插入進去了。

?測試:


刪除pos節點

/刪除pos節點
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead && *pphead);assert(pos);if (pos == *pphead){//如果等于說明要刪除的就是頭節點,所以我們直接頭刪SLTPopFront(pphead);}else{SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);pos = NULL;}
}

刪除指定pos節點的實現和我們在指定位置之前插入數據的實現有點相似。

當跳出while循序的時候說明prev->next已經等于pos了,所以我們讓perv->next指向pos的下一個節點,然后把pos釋放掉。

測試:


刪除pos之后的節點

//刪除pos之后的節點
void SLTEreaseAfter(SLTNode* pos)
{assert(pos && pos->next);SLTNode* del = pos->next;pos->next = del->next;free(del);del = NULL;
}

刪除pos之后的節點,直接把pos指向的下一個節點的地址保存起來,這里面我們定義了一個指針變量用來存放下一個節點,然后把del節點的next指向的節點給pos->next,最后釋放掉del。

測試:


銷毀鏈表

//銷毀鏈表
void SListDesTroy(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* pcur = *pphead;while (pcur){SLTNode* next = pcur->next;free(pcur);pcur = next;}*pphead = NULL;
}

通過循序對節點一個一個的釋放。

最后置為NULL


3.單鏈表的所有代碼

SList.h

#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>//定義節點的結構
typedef int SLTDataType;typedef struct SListNode
{SLTDataType date;//數據struct SListNode* next;//指向節點的地址}SLTNode;void SLTPrint(SLTNode* phead);//打印void SLTBuyBode(SLTNode** pphead, SLTDataType x);//尾插void SLPushFront(SLTNode** pphead, SLTDataType x);//頭插void SLTPopBack(SLTNode** pphead);//尾刪void SLTPopFront(SLTNode** pphead);//頭刪SLTNode* SLFind(SLTNode* phead, SLTDataType x);//查找void SLTnsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);//指定位置之前插入數據void SLTnesertAfter(SLTNode* pos, SLTDataType x);//指定位置之后插入數據void SLTErase(SLTNode** pphead, SLTNode* pos);//刪除pos節點void SLTEreaseAfter(SLTNode* pos);//刪除pos之后的節點void SListDesTroy(SLTNode** pphead);//銷毀鏈表

SList.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "SList.h"
void SLTPrint(SLTNode* phead)
{SLTNode* pcur = phead;while (pcur){printf("%d->", pcur->date);pcur = pcur->next;}printf("NULL\n");
}//判斷是否為非空鏈表
SLTNode* SLBuyNode(SLTDataType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("malloc fail!");exit(1);}newnode->date = x;newnode->next = NULL;return newnode;
}//尾插
void SLTBuyBode(SLTNode** pphead, SLTDataType x)
{assert(pphead);//*pphead就是指向第一個節點的指針//空鏈表和非空鏈表SLTNode* newnode = SLBuyNode(x);if (*pphead == NULL){*pphead = newnode;}else{//找尾SLTNode* ptail = *pphead;while (ptail->next){ptail = ptail->next;}//ptail指向的就是尾節點ptail->next = newnode;}
}//頭插
void SLPushFront(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newnode = SLBuyNode(x);newnode->next = *pphead;*pphead = newnode;
}//尾刪
void SLTPopBack(SLTNode** pphead)
{assert(pphead && *pphead);//鏈表只有一個節點if ((*pphead)->next == NULL)//-->優先級*{free(*pphead);*pphead = NULL;}else{//鏈表有多個節點SLTNode* prev = *pphead; //尾節點的前一個節點SLTNode* ptail = *pphead;//尾節點while (ptail->next){prev = ptail;//尾節點的前一個節點ptail = ptail->next;}free(ptail);ptail = NULL;prev->next = NULL;//讓我的尾節點指向空指針}
}
//頭刪
void SLTPopFront(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* next = (*pphead)->next;free(*pphead);*pphead = next;
}//查找
SLTNode* SLFind(SLTNode* phead, SLTDataType x)
{SLTNode* pcur = phead;while (pcur){if (pcur->date == x){return pcur;}pcur = pcur->next;}return  NULL;
}//指定位置之前插入數據
void SLTnsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{assert(pphead && *pphead);assert(pos);SLTNode* newnode = SLBuyNode(x);if (pos == *pphead){//如果pos等于我們的頭節點我們直接使用頭插SLPushFront(pphead, x);}else{SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}newnode->next = pos;prev->next = newnode;}
}//指定位置之后插入數據
void SLTnesertAfter(SLTNode* pos, SLTDataType x)
{assert(pos);SLTNode* newnode = SLBuyNode(x);newnode->next = pos->next;pos->next = newnode;
}//刪除pos節點
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead && *pphead);assert(pos);if (pos == *pphead){//如果等于說明要刪除的就是頭節點,所以我們直接頭刪SLTPopFront(pphead);}else{SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);pos = NULL;}
}//刪除pos之后的節點
void SLTEreaseAfter(SLTNode* pos)
{assert(pos && pos->next);SLTNode* del = pos->next;pos->next = del->next;free(del);del = NULL;
}//銷毀鏈表
void SListDesTroy(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* pcur = *pphead;while (pcur){SLTNode* next = pcur->next;free(pcur);pcur = next;}*pphead = NULL;
}

text.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "SList.h"
void SListText02()
{SLTNode* plist = NULL;//尾插SLTBuyBode(&plist, 1);SLTBuyBode(&plist, 2);SLTBuyBode(&plist, 3);SLTBuyBode(&plist, 4);SLTPrint(plist);//打印//測試頭插SLPushFront(&plist, 0);SLTPrint(plist);//測試尾刪SLTPopBack(&plist);SLTPrint(plist);//測試頭刪SLTPopFront(&plist);SLTPrint(plist);//測試查找SLTNode* find = SLFind(plist,1);if (find == NULL){printf("沒找到\n");}else{printf("找到了\n");}//指定位置之前插入數據SLTnsert(&plist,find,6);SLTPrint(plist);//指定位置之后插入數據SLTnesertAfter(find, 7);SLTPrint(plist);//刪除pos節點SLTErase(&plist,find);SLTPrint(plist);//刪除pos之后的節點SLTEreaseAfter(find);SLTPrint(plist);//銷毀鏈表SListDesTroy(&plist);
}
int main()
{SListText02();return 0;
}

以上就是單鏈表的基本操作了,如有表述不準確或理解不深刻的地方,還請各位看客不吝指正。

?

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

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

相關文章

OpenMesh 最長邊細分算法

文章目錄 一、簡介二、實現代碼三、實現效果參考資料一、簡介 這是一個很簡單的算法,其特點在于使用“最長邊”(LongestEdge)的某個閾值(T)作為細分的標準,并且這個細分是均勻進行的,即盡量保持各個部分的密度或復雜度相近。 具體的算法描述: 輸入:一個初始的圖形或網…

嵌入式—STC芯片開發板點亮第一盞燈

&#x1f3ac; 秋野醬&#xff1a;《個人主頁》 &#x1f525; 個人專欄:《Java專欄》《Python專欄》 ??心若有所向往,何懼道阻且長 文章目錄 一&#xff1a; 原理圖二&#xff1a; 需求實現三&#xff1a;編碼實現四&#xff1a;代碼實現五&#xff1a;編譯燒錄運行 一&…

HTML哆啦A夢

目錄 寫在前面 HTML簡介 完整代碼 代碼分析 系列推薦 寫在最后 寫在前面 誰不想擁有一只可愛的叮當貓呢&#xff1f;本期小編給大家帶來了一個萌萌的哆啦A夢。 HTML簡介 HTML&#xff0c;即超文本標記語言&#xff0c;是構建網頁的基礎技術之一&#xff0c;它是一種標…

JavaEE初階-多線程進階2

文章目錄 前言一、CAS1.1 CAS的概念1.2 原子類1.3 CAS的ABA問題 二、JUC中常用類2.1 Callable接口2.2 ReentrantLock&#xff08;可重入&#xff09;2.3 Semaphore信號量2.4 CountDownLatch類2.5 CopyOnWriteArrayList類2.6 ConcurrentHashMap 前言 對于多線程進階的部分&…

Scala學習之 控制結構和函數

目錄 第二章 控制結構和函數1- 條件表達式2- 語句終止3- 塊表達式和賦值4- 輸入和輸出5- 循環6- 高級for循環和for推到式7- 函數8- 默認參數和帶名參數9- 可變參數10- 過程11- 懶值12- 異常end 第二章 控制結構和函數 1- 條件表達式 Scala的 if/esle 語法結構與java一樣, 但是…

C語言例題43、打印倒立金字塔

#include <stdio.h>void main() {int i, j;for (i 5; i > 0; i--) {for (j 5; j > i; j--) {//輸出空格printf(" ");}for (j 2 * i; j > 1; j--) {//輸出星號printf("* ");}printf("\n");} }運行結果&#xff1a; 本章C語言…

用好 explain 媽媽再也不用擔心我的 SQL 慢了

大家好&#xff0c;我是聰&#xff0c;一個樂于分享的小小程序員。在不久之前我寫了一個慢 SQL 分析工具&#xff0c;可以用來分析 Java Mybatis 項目的 SQL 執行情況&#xff0c;其中剛好涉及到了 explain 的使用。感興趣的可以了解一下。 Github 地址?&#xff1a;https://…

【C#】學習獲取程序執行路徑,Gemini 幫助分析

一、前言&#xff1a; 在Delphi中&#xff0c;如果想要獲取當前執行程序的目錄&#xff0c;程序代碼如下&#xff1a; ExtractFilePath(ParamStr(0)); 今天在分析一個別人做的C#程序時看到了一段C#代碼&#xff0c;意思是獲取執行程序所在的文件目錄&#xff1a; public stat…

基于區塊鏈的Web 3.0關鍵技術研討會順利召開

基于區塊鏈的Web3.0關鍵技術研討會 2024年4月23日&#xff0c;由國家區塊鏈技術創新中心主辦的“基于區塊鏈的web3.0關鍵技術研討會”召開。Web3.0被用來描述一個運行在“區塊鏈”技術之上的“去中心化”的互聯網&#xff0c;該網絡上的主體掌握自己數據所有權和使用權&#xf…

【回眸】git VS repo 區別

git VS repo 區別 1. git&#xff1a;Git是一個開源的分布式版本控制系統&#xff0c;用以有效、高速的處理從很小到非常大的項目版本管理。 2. Repo: Repo是谷歌用Python腳本寫的調用git的一個腳本,Repo實現管理多個git庫。 Git 常用命令 1. git init&#xff1a;在當前目…

【原創】java+springboot+mysql企業郵件管理系統設計與實現

個人主頁&#xff1a;程序猿小小楊 個人簡介&#xff1a;從事開發多年&#xff0c;Java、Php、Python、前端開發均有涉獵 博客內容&#xff1a;Java項目實戰、項目演示、技術分享 文末有作者名片&#xff0c;希望和大家一起共同進步&#xff0c;你只管努力&#xff0c;剩下的交…

Vue的學習 —— <vue組件>

目錄 前言 正文 一、選項式API與組合式API 二、生命周期函數 1、onBeforeMount() 2、onMounted() 3、onBeforeUpdate() 4、onUpdated() 5、onBeforeUnmount() 6、onUnmounted() 三、組件之間的樣式沖突 四、父組件向子組件傳遞數據 1、定義props 2、靜態綁定props…

C++青少年簡明教程:賦值語句

C青少年簡明教程&#xff1a;賦值語句 賦值語句是編程中最基本也是最常用的概念之一&#xff0c;它用于將一個值分配給一個變量。 使用等號&#xff08; 稱為賦值運算符&#xff09;來給變量賦值&#xff0c;賦值語句的左邊是要賦值的變量&#xff0c;右邊是要賦給變量的值。C…

Docker 使用 CentOS 鏡像

使用 docker run 直接運行 CentOS 7 鏡像&#xff0c;并登錄 bash。 C:\Users\yhu>docker run -it centos:centos7 bash Unable to find image centos:centos7 locally centos7: Pulling from library/centos 2d473b07cdd5: Pull complete Digest: sha256:be65f488b7764ad36…

GPT-4o:全面深入了解 OpenAI 的 GPT-4o

GPT-4o&#xff1a;全面深入了解 OpenAI 的 GPT-4o 關于 GPT-4o 的所有信息ChatGPT 增強的用戶體驗改進的多語言和音頻功能GPT-4o 優于 Whisper-v3M3Exam 基準測試中的表現 GPT-4o 的起源追蹤語言模型的演變GPT 譜系&#xff1a;人工智能語言的開拓者多模式飛躍&#xff1a;超越…

連接虛擬機的 redis

用Windows 的 Redis Insight 連接虛擬機的 安裝redis發現連不上 我的redis是新安裝&#xff0c;沒有用戶名密碼&#xff0c;發現是ip問題 127 開頭的被我注釋了&#xff0c;換成了ifconfig查到的ip

vim命令大全(基礎版)

創建一個py文件 vim cs.py一、命令模式 按Esc后&#xff0c;按shift&#xff1a;進入命令模式 :wq # 保存并退出 :q # 退出 :q! # 強制退出 :%d # 刪除全部內容按兩下d&#xff0c;刪除光標所在行 按兩下y&#xff0c;復制光標所在行 按一下p&#xff0c;粘貼復制內容到下…

Android性能:SurfaceFlinger與BufferQueue(3)

Android性能&#xff1a;SurfaceFlinger與BufferQueue&#xff08;3&#xff09; Android顯示系統的組成可以概括為兩大部分&#xff1a;繪制(DrawFrame)合成&#xff08;SurfaceFlinger HWC&#xff09; 繪制&#xff1a;Surface中空的 GraphicBuffer->CPU或者GPU通過Canv…

Python GUI開發- Qt Designer環境搭建

前言 Qt Designer是PyQt5 程序UI界面的實現工具&#xff0c;使用 Qt Designer 可以拖拽、點擊完成GUI界面設計&#xff0c;并且設計完成的 .ui 程序可以轉換成 .py 文件供 python 程序調用 環境準備 使用pip安裝 pip install pyqt5-toolsQt Designer 環境搭建 在pip安裝包…

Vue 常見通信

Vue 常見通信 1、父子通信 父傳子 props&#xff0c;子傳父 events&#xff08;$emit&#xff09;&#xff1b; 通過父鏈 / 子鏈 通信$parent / $children&#xff1b; $refs獲取ref 可以訪問組件實例方法&#xff0c;&#xff1b; 提供與注射provide / inject a t t r s …