數據結構 -- 鏈表--雙向鏈表的特點、操作函數

雙向鏈表的操作函數

DouLink.c
#include "DouLink.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>/*** @brief 創建一個空的雙向鏈表* * 動態分配雙向鏈表管理結構的內存,并初始化頭指針和節點計數* * @return 成功返回指向新鏈表的指針,失敗返回NULL*/
DouLinkList *CreateDouLinkList()
{// 為鏈表管理結構分配內存DouLinkList *dl = malloc(sizeof(DouLinkList));if (NULL == dl){perror("CreateDouLinkList malloc");  // 分配失敗時輸出錯誤信息return NULL;}dl->head = NULL;  // 初始化頭指針為空(空鏈表)dl->clen = 0;     // 初始化節點計數為0return dl;
}/*** @brief 在雙向鏈表頭部插入新節點* * 動態創建新節點,將數據存入節點并插入到鏈表頭部* * @param dl 指向雙向鏈表的指針* @param data 指向要插入的數據的指針* @return 成功返回0,失敗返回1*/
int InsertHeadDouLinkList(DouLinkList *dl, DATATYPE *data)
{// 為新節點分配內存DouLinkNode *newnode = malloc(sizeof(DouLinkNode));if (NULL == newnode){perror("InsertHeadDouLinkList malloc\n");  // 分配失敗時輸出錯誤信息return 1;}// 復制數據到新節點memcpy(&newnode->data, data, sizeof(DATATYPE));newnode->next = NULL;  // 初始化新節點的后繼指針newnode->prev = NULL;  // 初始化新節點的前驅指針// 如果鏈表為空,直接將新節點作為頭節點if (IsEmptyDouLinkList(dl)){dl->head = newnode;}// 否則將新節點插入到頭部else{newnode->next = dl->head;       // 新節點的后繼指向原頭節點dl->head->prev = newnode;       // 原頭節點的前驅指向新節點dl->head = newnode;             // 更新頭指針為新節點}dl->clen++;  // 節點計數加1return 0;
}/*** @brief 在雙向鏈表尾部插入新節點* * 動態創建新節點,將數據存入節點并插入到鏈表尾部* * @param dl 指向雙向鏈表的指針* @param data 指向要插入的數據的指針* @return 成功返回0,失敗返回1*/
int InsertTailDouLinkList(DouLinkList *dl, DATATYPE *data)
{// 如果鏈表為空,直接調用頭部插入函數if (IsEmptyDouLinkList(dl)){return InsertHeadDouLinkList(dl, data);}// 否則在尾部插入else{// 為新節點分配內存DouLinkNode *newnode = malloc(sizeof(DouLinkNode));if (NULL == newnode){perror("InsertTailDouLinkList malloc\n");  // 分配失敗時輸出錯誤信息return 1;}// 復制數據到新節點memcpy(&newnode->data, data, sizeof(DATATYPE));newnode->next = NULL;  // 新節點的后繼為空(作為尾節點)newnode->prev = NULL;  // 初始化前驅指針// 找到當前尾節點DouLinkNode *tmp = dl->head;while (tmp->next)  // 遍歷到最后一個節點{tmp = tmp->next;}// 將新節點鏈接到尾節點后newnode->prev = tmp;  // 新節點的前驅指向原尾節點tmp->next = newnode;  // 原尾節點的后繼指向新節點}dl->clen++;  // 節點計數加1return 0;
}/*** @brief 在雙向鏈表指定位置插入新節點* * 在鏈表的指定索引位置插入新節點,索引從0開始* * @param dl 指向雙向鏈表的指針* @param data 指向要插入的數據的指針* @param pos 插入位置的索引* @return 成功返回0,失敗返回1*/
int InsertPosDouLinkList(DouLinkList *dl, DATATYPE *data, int pos)
{int size = GetSizeDouLinkList(dl);// 檢查位置是否合法if (pos < 0 || pos > size){printf("InsertPosDouLinkList pos error\n");return 1;}// 位置0等同于頭部插入if (0 == pos){return InsertHeadDouLinkList(dl, data);}// 位置等于鏈表長度等同于尾部插入else if (size == pos){return InsertTailDouLinkList(dl, data);}// 中間位置插入else{// 為新節點分配內存,注意只能再此處為該新節點的分配內存,(因為如果上面的條件符合,調用頭插或尾插函數時就會有分配內存這一操作,如果一開始就為該新節點分配內存可能會導致段錯誤)DouLinkNode *newnode = malloc(sizeof(DouLinkNode));if (NULL == newnode){perror("InsertPosDouLinkList malloc\n");  // 分配失敗時輸出錯誤信息return 1;}// 復制數據到新節點memcpy(&newnode->data, data, sizeof(DATATYPE));newnode->next = NULL;newnode->prev = NULL;// 找到要插入位置的節點DouLinkNode *tmp = dl->head;while (pos--)  // 移動到目標位置{tmp = tmp->next;}// 插入新節點newnode->next = tmp;            // 新節點的后繼指向當前節點newnode->prev = tmp->prev;      // 新節點的前驅指向當前節點的前驅tmp->prev = newnode;            // 當前節點的前驅指向新節點newnode->prev->next = newnode;  // 當前節點原前驅的后繼指向新節點}dl->clen++;  // 節點計數加1return 0;
}/*** @brief 顯示雙向鏈表中的所有節點數據* * 可以按照正向或反向遍歷并打印鏈表中的所有數據* * @param dl 指向雙向鏈表的指針* @param direct 遍歷方向(正向或反向)* @return 成功返回0*/
int ShowDouLinkList(DouLinkList *dl, DIRECT direct)
{DouLinkNode *tmp = dl->head;// 正向遍歷(從頭部到尾部)if (DIR_FORWARD == direct){while (tmp)  // 遍歷所有節點{// 打印節點數據printf("name:%s sex:%c age:%d score:%d\n", tmp->data.name, tmp->data.sex, tmp->data.age, tmp->data.score);tmp = tmp->next;  // 移動到下一個節點}}// 反向遍歷(從尾部到頭部)else{// 先移動到尾節點while (tmp->next){tmp = tmp->next;}// 從尾節點遍歷到頭部while (tmp){// 打印節點數據printf("name:%s sex:%c age:%d score:%d\n", tmp->data.name, tmp->data.sex, tmp->data.age, tmp->data.score);tmp = tmp->prev;  // 移動到前一個節點}}return 0;
}/*** @brief 判斷雙向鏈表是否為空* * @param dl 指向雙向鏈表的指針* @return 鏈表為空返回1,不為空返回0*/
int IsEmptyDouLinkList(DouLinkList *dl)
{return 0 == dl->clen;  // 通過節點計數判斷是否為空
}/*** @brief 按姓名查找雙向鏈表中的節點(舊版實現,通過姓名直接匹配,可與函數指針回調版對比)* * 遍歷雙向鏈表,逐個對比節點中存儲的姓名與傳入的目標姓名,找到則返回對應節點指針,用于簡單的按姓名精準查找場景。* 若后續有多樣化查找需求(比如按年齡、分數等),更推薦用函數指針回調的通用查找方式( FindDouLinkList 函數)。* * @param dl 指向要操作的雙向鏈表管理結構的指針,通過它能訪問鏈表頭節點,進而遍歷整個鏈表* @param name 要查找的目標姓名,以字符串形式傳入,用于和鏈表節點中存儲的姓名做對比* @return 找到匹配姓名的節點時,返回該節點的指針;遍歷完鏈表未找到時,返回 NULL */
DouLinkNode *FindDouLinkList(DouLinkList *dl, char *name)
{DouLinkNode* tmp = dl->head;  // 從鏈表頭節點開始遍歷while (tmp)  // 只要當前節點指針不為空,就持續遍歷{// 調用 strcmp 函數對比當前節點姓名和目標姓名,strcmp 返回 0 表示字符串相等if (0 == strcmp(tmp->data.name, name))  {return tmp;  // 找到匹配姓名的節點,返回該節點指針}tmp = tmp->next;  // 移動到下一個節點,繼續遍歷}return NULL;  // 遍歷完所有節點都沒找到匹配姓名的,返回 NULL
}/*** @brief 在雙向鏈表中查找符合條件的節點* * 使用回調函數作為匹配條件,實現靈活的查找功能* * @param dl 指向雙向鏈表的指針* @param fun 回調函數指針,用于判斷節點是否符合條件* @param arg 傳遞給回調函數的參數,作為查找條件* @return 找到返回匹配節點的指針,未找到返回NULL*/
DouLinkNode *FindDouLinkList(DouLinkList *dl, PFUN fun, void *arg)
{DouLinkNode *tmp = dl->head;  // 從頭部開始遍歷while (tmp)  // 遍歷所有節點{// 調用回調函數判斷當前節點是否符合條件if (fun(&tmp->data, arg)){return tmp;  // 找到匹配節點,返回該節點指針}tmp = tmp->next;  // 移動到下一個節點}return NULL;  // 未找到匹配節點
}/*** @brief 反轉雙向鏈表* * 將雙向鏈表的節點順序反轉,改變節點間的鏈接關系* * @param dl 指向雙向鏈表的指針* @return 成功返回0,無需反轉返回1*/
int ReverseDouLinkList(DouLinkList *dl)
{int size = GetSizeDouLinkList(dl);// 節點數小于2時無需反轉if (size < 2){printf("No need to reverse (size < 2)\n");return 1;}DouLinkNode *cur = dl->head;  // 當前節點指針,從頭部開始DouLinkNode *Prev = NULL;     // 保存前一個節點的指針while (cur != NULL){  DouLinkNode *tmp = cur->next;  // 保存下一個節點,防止斷鏈cur->next = Prev;              // 反轉當前節點的后繼指針,指向前一個節點cur->prev = tmp;               // 反轉當前節點的前驅指針,指向后一個節點Prev = cur;                    // 更新前一個節點指針cur = tmp;                     // 移動到下一個節點}dl->head = Prev;  // 反轉后,原尾節點成為新的頭節點return 0;
}/*** @brief 獲取雙向鏈表的節點數量* * @param dl 指向雙向鏈表的指針* @return 返回鏈表中的節點數量*/
int GetSizeDouLinkList(DouLinkList *dl)
{return dl->clen;  // 直接返回節點計數值
}/*** @brief 修改雙向鏈表中符合條件的節點數據* @param dl 雙向鏈表的指針* @param fun 比較函數指針,用于查找目標節點* @param arg 傳給比較函數的參數(用于指定查找條件)* @param newdata 指向新數據的指針,將用此數據替換找到節點的數據* @return 0表示修改成功,1表示修改失敗(未找到節點)*/
int ModifyDouLinkList(DouLinkList *dl, PFUN fun, void *arg, DATATYPE *newdata)
{// 調用查找函數,根據fun和arg找到目標節點DouLinkNode *tmp = FindDouLinkList(dl, fun, arg);// 若未找到目標節點,打印錯誤信息并返回失敗if (NULL == tmp){printf("ModifyDouLinkList failure failure\n");return 1;}// 將新數據拷貝到找到的節點中(覆蓋原有數據)// 使用memcpy確保結構體所有成員都被正確替換memcpy(&tmp->data, newdata, sizeof(DATATYPE));// 修改成功,返回0return 0;
}/*** @brief 從雙向鏈表中刪除符合條件的節點* @param dl 雙向鏈表的指針* @param fun 比較函數指針,用于查找目標節點* @param arg 傳給比較函數的參數(用于指定查找條件)* @return 0表示刪除成功,1表示刪除失敗(未找到節點)*/
int DeleteDouLinkList(DouLinkList *dl, PFUN fun, void *arg)
{// 調用查找函數,根據fun和arg找到目標節點DouLinkNode *tmp = FindDouLinkList(dl, fun, arg);// 若未找到目標節點,打印錯誤信息并返回失敗if (NULL == tmp){printf("del failure\n");return 1;}// 情況1:刪除的是頭節點if (tmp == dl->head){// 將頭指針指向原頭節點的下一個節點dl->head = dl->head->next;// 若新頭節點存在,需要將其prev指針置為NULL(斷開與原頭節點的聯系)if (dl->head){dl->head->prev = NULL;}}// 情況2:刪除的是中間節點或尾節點else{// 若當前節點不是尾節點,需要將下一個節點的prev指向當前節點的前一個節點if (tmp->next){tmp->next->prev = tmp->prev;}// 將當前節點前一個節點的next指向當前節點的下一個節點tmp->prev->next = tmp->next;}// 釋放被刪除節點的內存,避免內存泄漏free(tmp);// 鏈表長度減1dl->clen--;// 刪除成功,返回0return 0;
}/*** @brief 銷毀整個雙向鏈表,釋放所有分配的內存* @param dl 雙向鏈表的指針* @return 0表示銷毀成功*/
int DestroyDouLinkList(DouLinkList *dl)
{DouLinkNode *tmp = NULL;// 循環刪除鏈表中的所有節點while (1){// 每次獲取當前頭節點tmp = dl->head;// 若頭節點為NULL,說明所有節點已刪除,退出循環if (NULL == tmp){break;}// 將頭指針移動到下一個節點dl->head = dl->head->next;// 釋放當前頭節點的內存free(tmp);}// 釋放鏈表結構體本身的內存free(dl);// 銷毀成功,返回0return 0;
}

雙向鏈表特點

雙向鏈表(Doubly Linked List)是一種更復雜的鏈表,它的每個節點不僅包含指向下一個節點的指針(next),還包含指向前一個節點的指針(prev)。

  1. 雙向遍歷

    • 核心特點:可以從頭節點開始向后遍歷,也可以從尾節點開始向前遍歷。這是其與單向鏈表最根本的區別。

  2. 節點結構

    • 每個節點包含三部分:

      • data: 存儲數據。

      • next: 指針,指向下一個節點。

      • prev: 指針,指向前一個節點。

  3. 操作效率(與單向鏈表對比的核心優勢)

    • 刪除特定節點:在已知某個節點指針的情況下,雙向鏈表可以在 O(1) 時間內刪除該節點,因為它可以直接通過?prev?指針找到前驅節點。而單向鏈表需要從頭遍歷才能找到前驅節點,時間復雜度為 O(n)。

    • 在特定節點前插入:同樣,在已知某個節點指針的情況下,雙向鏈表可以在 O(1) 時間內完成在其前面的插入操作。單向鏈表無法直接做到,仍需遍歷尋找前驅節點。

    • 反向遍歷:需要反向遍歷鏈表(例如,從大到小輸出一個有序鏈表)時,雙向鏈表非常高效。單向鏈表則非常笨拙,通常需要借助棧等輔助數據結構,或者先反轉鏈表(這會修改原鏈表)。

  4. 缺點

    • 內存開銷:每個節點都需要一個額外的指針來存儲前驅節點的地址。對于節點數據本身很小的鏈表(例如,只存儲一個整數),這個額外的指針開銷占比會很大。

    • 操作復雜性:插入和刪除節點時,需要維護兩個方向的指針(next?和?prev),共需要修改?4?個指針(在某些邊界情況下是 2 個)。而單向鏈表只需要修改?1?或?2?個指針。代碼實現上更復雜,容易出錯。


與單向鏈表的對比

特性單向鏈表 (Singly Linked List)雙向鏈表 (Doubly Linked List)
節點結構data,?nextdata,?next,?prev
遍歷方向只能從頭到尾單向遍歷可以雙向遍歷(從頭到尾或從尾到頭)
內存占用更小(每個節點少一個指針)更大(每個節點多一個指針)
刪除操作刪除已知節點的前驅節點很高效 (O(1))
刪除已知節點本身需要找前驅,效率低 (O(n))
刪除已知節點本身非常高效 (O(1))
插入操作只能在已知節點后插入?(O(1))
在已知節點前插入需要找前驅,效率低 (O(n))
在已知節點前或后插入都非常高效 (O(1))
靈活性較低很高,前后移動都很方便
代碼復雜度相對簡單相對復雜,需要維護前后指針的完整性

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

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

相關文章

Wireshark獲取數據傳輸的碼元速率

一、Wireshark的物理層參數 Wireshark主界面可以看到數據發送時刻和長度&#xff1a; 這個時刻是Wireshark完整獲取數據包的時刻&#xff0c;實際上就是結束時刻。 需要知道的是&#xff1a; Wireshark工作在數據鏈路層及以上&#xff0c;它能解碼 以太網幀 / IP 包 / TCP…

11.1.3 完善注冊登錄,實現文件上傳和展示

1、完善注冊/登錄 1. 涉及的數據庫表單&#xff1a;user_info 2. 引用MySQL線程池&#xff0c;Redis線程池 3. 完善注冊功能 4. 完善登錄功能 2.1 涉及的數據庫表單&#xff1a;user_info 重新創建數據庫 #創建數據庫 DROP DATABASE IF EXISTS 0voice_tuchuang;CREATE D…

【Linux文件系統】目錄結構

有沒有剛進入Linux世界時&#xff0c;對著黑乎乎的終端&#xff0c;輸入一個 ls / 后&#xff0c;看著蹦出來的一堆名字 like bin, etc, usr&#xff0c;感覺一頭霧水&#xff0c;像是在看天書&#xff1f; 別擔心&#xff0c;你不是一個人。Linux的文件系統就像一個超級有條理…

螺旋槽曲面方程的數學建模與偏導數求解

螺旋槽曲面的數學描述 在鉆頭設計和機械加工領域,螺旋槽的幾何建模至關重要。螺旋槽通常由徑向截形繞軸做螺旋運動形成,其數學模型可通過參數方程和隱函數方程兩種方式描述。 設螺旋槽的徑向截形方程為: y=f(z)y = f(z)y=f(z) x=xcx = x_cx=xc? 其中 xcx_cxc? 為常數,…

線性回歸:機器學習中的基石

在機器學習的眾多算法中&#xff0c;線性回歸無疑是最基礎也是最常被提及的一種。它不僅在統計學中占有重要地位&#xff0c;而且在預測分析和數據建模中也發揮著關鍵作用。本文將深入探討線性回歸的基本概念、評估指標以及在實際問題中的應用&#xff0c;并通過一個模擬的氣象…

編程刷題-資料分發1 圖論/DFS

P2097 資料分發 1 題目描述 有一些電腦&#xff0c;一部分電腦有雙向數據線連接。 如果一個電腦得到數據&#xff0c;它可以傳送到的電腦都可以得到數據。 現在&#xff0c;你有這個數據&#xff0c;問你至少將其輸入幾臺電腦&#xff0c;才能使所有電腦得到數據。 輸入格式 第…

RabbitMQ:延時消息(死信交換機、延遲消息插件)

目錄一、死信交換機【不推薦】二、延遲消息插件【推薦】2.1 安裝插件【Linux】2.2 安裝插件【Windows】2.3 如何使用延時消息&#xff1a;生產者發送消息時指定一個時間&#xff0c;消費者不會立刻收到消息&#xff0c;而是在指定時間之后才收到消息。 延時任務&#xff1a;設置…

動學學深度學習05-深度學習計算

動學學深度學習pytorch 參考地址&#xff1a;https://zh.d2l.ai/ 文章目錄動學學深度學習pytorch1-第05章-深度學習計算1. 層&#xff08;Layer&#xff09;與塊&#xff08;Block&#xff09;1.1 什么是深度學習中的“層”&#xff1f;1.2 什么是“塊”&#xff08;Block&…

智慧工廠煙霧檢測:全場景覆蓋與精準防控

智慧工廠煙霧檢測&#xff1a;構建工業安全的智能防線&#xff08;所有圖片均為真實項目案例&#xff09;在工業4.0時代&#xff0c;智慧工廠通過物聯網、人工智能與大數據技術的深度融合&#xff0c;實現了生產流程的數字化與智能化。然而&#xff0c;工廠環境中的火災隱患始終…

@JsonIgnoreProperties注解詳解

JsonIgnoreProperties是 Jackson 庫中的一個重要注解&#xff0c;用于在 JSON 序列化&#xff08;對象轉 JSON&#xff09;和反序列化&#xff08;JSON 轉對象&#xff09;過程中??控制屬性的可見性??。它提供了更高級別的屬性忽略能力&#xff0c;特別適合處理復雜場景。一…

紅酒數據集預處理實戰:缺失值處理的 5 種打開方式,從入門到進階一步到位

在數據分析與建模流程中&#xff0c;缺失值處理是數據預處理階段的關鍵步驟&#xff0c;直接影響后續模型的準確性與穩定性。本文以紅酒數據集為研究對象&#xff0c;詳細介紹如何通過基礎統計方法&#xff08;均值、中位數、眾數&#xff09;、完整案例分析&#xff08;CCA&am…

Node.js 開發 JavaScript SDK 包的完整指南(AI)

一、核心概念SDK 包定義 專為特定服務/平臺封裝的工具庫&#xff0c;提供標準化 API 調用、錯誤處理、類型聲明等功能。示例&#xff1a;支付寶 SDK、AWS SDK、微信小程序 SDK。技術棧選擇 語言&#xff1a;JavaScript/TypeScript&#xff08;推薦 TS&#xff0c;便于類型提示&…

Redis實戰-基于Session實現分布式登錄

1.流程分析1.1發送短信驗證碼提交手機號的時候要進行校驗手機號&#xff0c;校驗成功才會去生成驗證碼&#xff0c;將驗證碼保存到session&#xff0c;發生他把這部分那。1.2短信驗證碼登錄/注冊如果提交手機號和驗證碼之后&#xff0c;校驗一致才進行根據手機號查詢用戶&#…

瘋狂星期四文案網第47天運營日記

網站運營第47天&#xff0c;點擊觀站&#xff1a; 瘋狂星期四 crazy-thursday.com 全網最全的瘋狂星期四文案網站 運營報告 今日訪問量 今日搜索引擎收錄情況 必應現在是邊收錄邊k頁面 百度快倒閉 網站優化點 完善工作流&#xff0c;全面實現文案自動化采集&#xff0c;se…

Vue生命周期以及自定義鉤子和路由

Vue生命周期常用的onMounted掛載后執行和onUnmounted卸載前以及onupdated更新后實際上用react對比就是useEffect&#xff0c;而且掛載順序也是子組件先于父組件然后往外的棧結構&#xff0c;先進后出。1.Vue的生命周期<template><h2>當前求和為{{ sum }}</h2>…

探索Thompson Shell:Unix初代Shell的智慧

引言 在計算機科學的漫漫長河中&#xff0c;Thompson Shell 無疑占據著舉足輕重的開創性地位&#xff0c;它是 Unix 系統的第一個 shell&#xff0c;誕生于 1971 年&#xff0c;由計算機領域的傳奇人物 Ken Thompson 開發。在那個計算機技術剛剛起步、硬件資源極度匱乏的年代&a…

MySQL B+ 樹索引詳解:從原理到實戰優化

引言在現代數據庫應用中&#xff0c;查詢效率是影響系統性能的關鍵因素之一。而索引&#xff0c;尤其是 B 樹索引&#xff0c;是 MySQL 中最常用、最重要的性能優化手段。正確使用索引可以將查詢時間從毫秒級降低到微秒級&#xff0c;極大地提升應用響應速度。1. B 樹索引的重要…

計算機內存中的整型存儲奧秘、大小端字節序及其判斷方法

目錄 一、回顧與引入&#xff1a;整數在內存中的存儲方式 為什么要采用補碼存儲&#xff1f; 二、大小端字節序及其判斷方法 1、什么是大小端&#xff1f; 2、為什么存在大小端&#xff1f; 3、練習 練習1&#xff1a;簡述大小端概念并設計判斷程序&#xff08;百度面試…

Redis 最常用的 5 種數據類型

Redis 支持多種靈活的數據類型&#xff0c;每種類型針對特定場景優化。以下是 **Redis 最常用的 5 種數據類型**及其核心特點和應用場景&#xff1a;1. 字符串&#xff08;String&#xff09;描述&#xff1a;最基本的數據類型&#xff0c;可存儲文本、數字&#xff08;整數/浮…

【嵌入式】RK3588 對比 NVIDIA Jetson,Radxa Rock 5B vs Orange Pi 5 Max

RK3588這個芯片,適合AI應用么,為什么這么貴呢 AI 邊緣盒子里的旗艦芯 深度分析一下 RK3588(瑞芯微 Rockchip RK3588) 為什么被很多人關注在 AI 應用,以及它價格偏高的原因。 ?? 1. RK3588 的基本情況 制程:8nm(Samsung 8nm LP) CPU:8 核 big.LITTLE 架構(4 Cortex-…