線性表:包含零個(gè)或多個(gè)數(shù)據(jù)元素的有限序列。
線性鏈表:指的是使用數(shù)組代替指針,來(lái)描述單鏈表;每個(gè)數(shù)據(jù)項(xiàng)含有data和cur屬性,data是數(shù)據(jù)的值,cur相當(dāng)于指向下一個(gè)節(jié)點(diǎn)的指針。
線性表特性:
- 是一個(gè)序列,元素直接是有順序的。
- 表中元素個(gè)數(shù)叫表長(zhǎng),元素個(gè)數(shù)可以有多個(gè),也可以為0。
- 某個(gè)元素的上一個(gè)元素叫直接前驅(qū)元素,下一個(gè)元素叫直接后繼元素。
鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)特點(diǎn)
使用帶數(shù)據(jù)域和指針域的節(jié)點(diǎn)存儲(chǔ)單個(gè)元素的值,并通過(guò)指針將所有元素連接起來(lái)。
優(yōu)點(diǎn):
- 擁有單鏈表類(lèi)似的特性。
- 插入和刪除元素的時(shí)候,只需要修改游標(biāo)。
- 改進(jìn)了順序存儲(chǔ)結(jié)構(gòu)中插入和刪除操作需要大量移動(dòng)元素的缺點(diǎn)。
缺點(diǎn):
- 沒(méi)有解決連續(xù)存儲(chǔ)分配帶來(lái)的表長(zhǎng)難以確定的問(wèn)題。
- 失去了順序存儲(chǔ)結(jié)構(gòu)隨機(jī)存取的特性。
時(shí)間復(fù)雜度
- 讀取時(shí)的時(shí)間復(fù)雜度為O(n)。
- 插入、刪除時(shí)的時(shí)間復(fù)雜度為O(1)。
數(shù)據(jù)項(xiàng)示意圖
空靜態(tài)鏈表示意圖
靜態(tài)鏈表插入元素示意圖
靜態(tài)鏈表刪除元素示意圖
實(shí)現(xiàn)代碼如下:
// 線性表(靜態(tài)鏈表)
#include <stdio.h>
#include <malloc.h>
#include <time.h>
#define OK 1 // 執(zhí)行成功
#define ERROR 0 // 執(zhí)行失敗
#define MAXSIZE 100 // 初始分配存儲(chǔ)空間
typedef int Status; // 函數(shù)返回結(jié)果類(lèi)型
typedef char ElemType; // 元素類(lèi)型
/**
* 靜態(tài)鏈表結(jié)構(gòu)
* 1. 數(shù)組最后一個(gè)元素的cur用來(lái)存放第一個(gè)插入元素的下標(biāo),
* 相當(dāng)于頭節(jié)點(diǎn),指向0時(shí)表示鏈表為空
* 2. 數(shù)組0下標(biāo)元素的cur用來(lái)存放下一個(gè)可用存儲(chǔ)位置的下標(biāo),
* 即下一個(gè)插入節(jié)點(diǎn)的位置
*/
typedef struct {
ElemType data; // 存放元素值
int cur; // 指向下一個(gè)節(jié)點(diǎn)的下標(biāo),為0表示無(wú)指向,即到達(dá)鏈表末尾
} Component, StaticLinkList[MAXSIZE];
/**
* 初始化靜態(tài)鏈表
* 將一維數(shù)組L的分量鏈接成一個(gè)備用鏈表,L[0].cur為頭指針,0表示空指針
* @param L 靜態(tài)鏈表
* @return 執(zhí)行狀態(tài)
*/
Status InitList(StaticLinkList L) {
int i; // 用于遍歷表元素
for (i = 0; i < MAXSIZE - 1; i++) {
L[i].cur = i + 1; // 設(shè)置每個(gè)位置的指針指向下一個(gè)元素的位置
}
// 鏈表中最后一個(gè)元素指向0(表示當(dāng)前第一個(gè)插入的節(jié)點(diǎn)下標(biāo)為0,此時(shí)鏈表為空)
L[MAXSIZE - 1].cur = 0;
return OK;
}
/**
* 獲取下一個(gè)可用存儲(chǔ)位置的下標(biāo)
* @param L 靜態(tài)鏈表
* @return 下一個(gè)可用存儲(chǔ)位置的下標(biāo),無(wú)可用存儲(chǔ)位置時(shí)返回0
*/
int Malloc_SSL(StaticLinkList L) {
int i = L[0].cur; // L中0位置cur存的值就是下一個(gè)可用存儲(chǔ)位置的下標(biāo)
// 當(dāng)前靜態(tài)鏈表未滿(mǎn)
if (L[0].cur) {
L[0].cur = L[i].cur; // 獲取下一個(gè)可用存儲(chǔ)位置的下標(biāo)
}
return i; // 返回下一個(gè)可用存儲(chǔ)位置的下標(biāo)
}
/**
* 釋放下標(biāo)為k的元素到備用鏈表
* 即讓下標(biāo)為k的元素成為下一個(gè)可插入節(jié)點(diǎn)
* @param L 靜態(tài)鏈表
* @param k 元素下標(biāo)
*/
void Free_SSL(StaticLinkList L, int k) {
L[k].cur = L[0].cur; // 讓k下標(biāo)元素的下一個(gè)元素指向原本的下一個(gè)可插入節(jié)點(diǎn)
L[0].cur = k; // 讓k下標(biāo)的元素成為下一個(gè)可插入節(jié)點(diǎn)
}
/**
* 獲取線性鏈表長(zhǎng)度
* @param L 線性鏈表
* @return 線性鏈表長(zhǎng)度
*/
int ListLength(StaticLinkList L) {
int j = 0; // 用于統(tǒng)計(jì)元素個(gè)數(shù)
int i = L[MAXSIZE - 1].cur; // 獲取第一個(gè)元素的下標(biāo)
// 遍歷鏈表元素
while (i) {
i = L[i].cur; // 獲取下一個(gè)元素的下標(biāo)
j++; //統(tǒng)計(jì)個(gè)數(shù)加1
}
return j; // 返回鏈表長(zhǎng)度
}
/**
* 在線性鏈表中指定位置插入新元素
* @param L 線性鏈表
* @param i 插入位置
* @param e 插入的值
* @return 執(zhí)行狀態(tài)
*/
Status ListInsert(StaticLinkList L, int i, ElemType e) {
int j, t; // j是下一個(gè)可插入位置的下標(biāo),t用于遍歷for循環(huán)
int k = MAXSIZE - 1; // 最后一個(gè)元素的下標(biāo)
// 插入位置下標(biāo)越界,插入失敗
if (i < 1 || i > ListLength(L) + 1) {
return ERROR;
}
j = Malloc_SSL(L); // 獲取下一個(gè)可插入位置的下標(biāo)
// 線性鏈表未滿(mǎn)(j不為0)
if (j) {
L[j].data = e; // 將e賦值給下一個(gè)可插入節(jié)點(diǎn)的值(j下標(biāo)的元素表示新節(jié)點(diǎn))
// 遍歷線性鏈表,找到插入位置的上一個(gè)節(jié)點(diǎn)
for (t = 1; t <= i - 1; t++) {
k = L[k].cur; // 獲取下一個(gè)元素的坐標(biāo)
}
L[j].cur = L[k].cur; // 新節(jié)點(diǎn)的指向插入位置前一個(gè)元素的下一個(gè)元素(即原本i位置的節(jié)點(diǎn))
L[k].cur = j; // 插入位置的上一個(gè)節(jié)點(diǎn)指向新節(jié)點(diǎn)
return OK;
}
return ERROR;
}
/**
* 刪除線鏈性表中指定位置的元素
* @param L 線性鏈表
* @param i 刪除位置的下標(biāo)
* @return 執(zhí)行狀態(tài)
*/
Status ListDelete(StaticLinkList L, int i) {
int j; // 用于遍歷元素
int k = MAXSIZE - 1; // 最后一個(gè)元素的下標(biāo)
// 插入位置下標(biāo)越界,插入失敗
if (i < 1 || i > ListLength(L) + 1) {
return ERROR;
}
// 遍歷線性鏈表,找到刪除位置的上一個(gè)節(jié)點(diǎn)
for (j = 1; j <= i - 1; j++) {
k = L[k].cur; // 獲取下一個(gè)元素的下標(biāo)
}
j = L[k].cur; // 獲取被刪除元素的下標(biāo)
L[k].cur = L[j].cur; // 【被刪除節(jié)點(diǎn)的上一個(gè)節(jié)點(diǎn)】指向【被刪除節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)】(即跳過(guò)被刪除節(jié)點(diǎn))
Free_SSL(L, j); // 釋放被刪除節(jié)點(diǎn)
return OK;
}
/**
* 打印單個(gè)元素
* @param e 元素值
* @return 執(zhí)行狀態(tài)
*/
Status visit(ElemType e) {
printf("%c ", e);
return OK;
}
/**
* 遍歷輸出線性鏈表中所有元素
* @param L 線性鏈表
* @return 執(zhí)行狀態(tài)
*/
Status ListTravel(StaticLinkList L) {
int i = L[MAXSIZE - 1].cur; // 獲取鏈表第一個(gè)元素的下標(biāo)
printf("[ ");
// 遍歷鏈表中所有元素
while (i) {
visit(L[i].data); // 打印單個(gè)節(jié)點(diǎn)的值
i = L[i].cur; // 獲取下一個(gè)節(jié)點(diǎn)的下標(biāo)
}
printf("]\n");
return OK;
}
int main() {
StaticLinkList L; // 線性鏈表
Status status; // 執(zhí)行狀態(tài)
status = InitList(L); // 初始化線性鏈表
printf("初始化后,L的長(zhǎng)度為:%d\n", ListLength(L));
status = ListInsert(L, 1, 'F');
status = ListInsert(L, 1, 'E');
status = ListInsert(L, 1, 'D');
status = ListInsert(L, 1, 'B');
status = ListInsert(L, 1, 'A');
printf("在L的表頭分別插入五個(gè)元素后,L中的值為:");
ListTravel(L); // 遍歷鏈表元素
printf("L的長(zhǎng)度為:%d\n", ListLength(L));
status = ListInsert(L, 3, 'C'); // 在第三個(gè)位置插入C元素
printf("在第三個(gè)位置插入一個(gè)元素C后,L中的值為:");
ListTravel(L); // 遍歷鏈表元素
printf("L的長(zhǎng)度為:%d\n", ListLength(L));
status = ListDelete(L, 4); // 刪除第四個(gè)位置的元素
printf("刪除第四個(gè)位置的元素D后,鏈表L中的值為:");
ListTravel(L); // 遍歷鏈表元素
printf("L的長(zhǎng)度為:%d\n", ListLength(L));
return 0;
}
運(yùn)行結(jié)果