基礎版(方法一)每次新增/刪除都重新分配記憶體,頻繁操作下效能低下。本版引入 預設容量 與 擴容步長 機制,參考 std::vector / ArrayList 思想:空間換時間,減少 malloc/free 與 memcpy 次數。
#ifndef __LISTARRAY_H__
#define __LISTARRAY_H__
#include "rtthread.h"
#include "finsh.h"
#define LISTDEFAULTSIZE 20 // 初始容量
#define LISTCHANGESIZE 10 // 每次擴容/縮容步長
typedef struct _List List;
struct _List {
void **pListPointArray; // 元素指標陣列
int Total; // 目前元素個數
int ChangeSize; // 擴容步長
int Size; // 目前分配容量
void (*Add)(List *pList, void *pListPoint);
void (*Remove)(List *pList, void *pListPoint);
void (*Delete)(void *pList);
};
// ---------- 內部靜態函數 ----------
static void ListDelete(void *pList) {
rt_free(((List *)pList)->pListPointArray);
rt_free(pList);
}
static void ListAdd(List *pList, void *pListPoint) {
void **tListPointArray;
// 1. 容量不足時擴容
if (pList->Size == pList->Total) {
pList->Size += pList->ChangeSize;
tListPointArray = rt_malloc(sizeof(int *) * pList->Size);
memcpy(tListPointArray, pList->pListPointArray, sizeof(int *) * pList->Total);
rt_free(pList->pListPointArray);
pList->pListPointArray = tListPointArray;
}
// 2. 尾端插入
pList->pListPointArray[pList->Total] = pListPoint;
pList->Total++;
}
static void ListRemove(List *pList, void *pListPoint) {
int pListIndex, tListIndex;
void **tListPointArray;
if (pList->Total == 0) return;
// 1. 原地移除:雙指標覆蓋法,O(n) 無額外分配
for (pListIndex = 0, tListIndex = 0; pListIndex < pList->Total; pListIndex++) {
if (pList->pListPointArray[pListIndex] != pListPoint) {
pList->pListPointArray[tListIndex] = pList->pListPointArray[pListIndex];
tListIndex++;
}
}
pList->Total = tListIndex;
// 2. 縮容判斷:剩餘元素遠小於容量時才縮容
if (pList->Total <= (pList->Size - pList->ChangeSize)) {
pList->Size -= pList->ChangeSize;
tListPointArray = rt_malloc(sizeof(int *) * pList->Size);
memcpy(tListPointArray, pList->pListPointArray, sizeof(int *) * pList->Total);
rt_free(pList->pListPointArray);
pList->pListPointArray = tListPointArray;
}
}
static List *ListCreate(void) {
List *pList = (List *)rt_malloc(sizeof(List));
pList->Total = 0;
pList->Size = LISTDEFAULTSIZE;
pList->ChangeSize = LISTCHANGESIZE;
pList->pListPointArray = rt_malloc(sizeof(int *) * LISTDEFAULTSIZE); // 修正:乘以指標大小
pList->Add = ListAdd;
pList->Remove = ListRemove;
pList->Delete = ListDelete;
return pList;
}
#endif
Size:目前已分配的總容量(槽位數)。ChangeSize:每次擴容/縮容的步長(預設 10)。Total == Size 時才觸發 realloc 邏輯(手動 malloc+memcpy+free)。Size += ChangeSize,後續多次 Add 直接使用預留空間,O(1) 尾端插入。Total--。Total <= Size - ChangeSize,即剩餘元素較少時才釋放多餘空間,避免頻繁震盪。LISTDEFAULTSIZE(20)個指標槽位。rt_malloc(LISTDEFAULTSIZE) → rt_malloc(sizeof(int *) * LISTDEFAULTSIZE)。| 指標 | 方法一(基礎版) | 方法二(優化版) |
|---|---|---|
| 新增(均攤) | O(n) 每次分配 | O(1) 均攤,僅擴容時 O(n) |
| 移除(均攤) | O(n) 每次分配 | O(n) 移動元素,縮容時額外 O(n) |
| 記憶體碎片 | 高(頻繁 malloc/free) | 低(大塊分配,較少釋放) |
| 峰值記憶體 | 精確佔用 | 預留 ChangeSize 槽位 |
realloc: 若平台支援,可替換 malloc+memcpy+free 為單次 realloc,更高效。std::vector 採用 2x 擴容,均攤效能更優,但嵌入式需權衡記憶體峰值。Get、IndexOf、Clear 等常用操作。_Generic 或巨集產生類型安全版本,避免 void* 強制轉換。引入容量與增量機制後,ListArray 從「教學級玩具」進化為「生產級可用」的動態陣列容器。核心思想——預留空間減少重分配、延遲縮容避免震盪——是所有高效動態陣列實作的共同基因。