鏈表與順序表的邏輯結構一致, 除了首尾節點/元素, 有一個直接前驅和后繼, 兩者物理結構不同, 鏈表由一個節點來存儲后繼節點的地址. 我相信面向對象語言中根據一個對象訪問其成員和父類等用的是同樣的存儲模式.
- 類型定義
typedef struct Node {
struct Node *pNext; // 指向后繼節點
int data; // 數據域
}NODE,*PNODE;
- 創建
PNODE creat_list() {
PNODE pHead = (PNODE)(malloc(sizeof(NODE))); // 頭結點, 指向首節點, 其數據域為空
if (NULL==pHead) {
exit(-1);
}
int length;
PNODE pNew;
PNODE pEnd = (PNODE)(malloc(sizeof(NODE)));
if (NULL==pEnd) {
exit(-1);
}
pHead->data = 0;
printf("請輸入長度:");
scanf("%d",&length);
pEnd = pHead;
for (int i=0; i<length; i++) {
int val;
printf("請輸入:");
scanf("%d",&val);
pNew = (PNODE)(malloc(sizeof(NODE)));
if (NULL==pNew) {
exit(-1);
}
pNew->data = val;
pNew->pNext = NULL;
pEnd->pNext = pNew;
pEnd = pNew;
}
return pHead;
}
- 遍歷
void traverse_list(PNODE pHead)
{
PNODE p = pHead->pNext;
while (NULL != p) {
printf("%d\n", p->data);
p = p->pNext;
}
return;
}
- 獲取長度
int length_list(PNODE pHead) {
PNODE p = pHead->pNext;
int length = 0; // 此處要初始化為0 不然就是1;
while (NULL!=p) {
++length;
p = p->pNext;
}
return length;
}
- 判空
int is_empty(PNODE pHead) {
if (NULL == pHead->pNext) {
return 1;
} else {
return 0;
}
}
- 插入
int insert_list(PNODE pHead, int post, int val) {
PNODE p = pHead;
int i = 0;
while (p && i < post-1) { // 這一步是為了找到第post-1個節點, 并p偏移到這個節點
p = p->pNext;
++i;
}
// 此時p已經指向了第post-1個節點
if (NULL==p->pNext || i>post-1) { // 條件1是當post特別大的時候, 條件2是當post<1的時候
printf("插入位置不合法");
return -1;
}
PNODE e = (PNODE)malloc(sizeof(NODE));
e->data = val;
e->pNext = p->pNext;
p->pNext = e;
return 1;
}
- 冒泡排序
void sort_list(PNODE pHead) {
int len = length_list(pHead);
PNODE p;
int i,j,t;
for (i = len - 2 ; i >= 0; --i) {
for (j = 0,p = pHead->pNext; j <= i; j++) {
// 取出第j個
if (p->data > p->pNext->data) {
t = p->data;
p->data = p->pNext->data;
p->pNext->data = t;
}
p=p->pNext;
}
}
return;
}
順序表和鏈表的存儲結構決定了各自的優劣.
查找: 順序表可以直接根據內存地址計算直接取得, 也就是用數組下標;鏈表則必須根據其已知節點指針一步步偏移取得, 其效率低于順序表.
存儲空間: 順序表必須預估一個初始內存大小, 在實際操作過程中內存大小可能需要改變,比較麻煩. 鏈表則不需要考慮.僅此一點就決定了鏈表的使用會比順序表會多一些.