線性表:動態連結串列
阿新 • • 發佈:2018-12-22
在資料結構中我們經常會用到連結串列來處理一些問題, 連結串列同順序表一樣, 包括靜態連結串列和動態連結串列, 靜態連結串列並不是很常用, 但動態連結串列的重要性是不言而喻的. 接下來我們看一下動態連結串列的基本操作, 以書上的資料為參考, 同時自己對動態連結串列增加了新的認識和總結
動態連結串列的基本操作
動態連結串列的定義
//定義一個動態連結串列
typedef int ElemType;
typedef struct LNode {
ElemType data;
struct LNode* next;
}LNode, *LinkList;
建立一個動態連結串列
//建立一個動態連結串列
void CreateList(LinkList* L, int len) {
printf("請輸入 %d 個數據:", len);
//建立連結串列的頭節點
*L = (LinkList)malloc(sizeof(LNode));
//定義一個指向尾節點的指標和一個指向建立結點的指標
LinkList rear = *L, p = NULL;
//建立指定大小的空間
for (int i = 1; i < len + 1; ++i) {
p = (LinkList)malloc(sizeof(LNode));
scanf("%d", &p->data);
//尾指標連線新結點
rear->next = p;
//改變尾指標位置
rear = p;
}
//尾指標之後為空
rear->next = NULL;
}
//逆序
//void CreateList(LinkList* L, int len) {
// printf("請輸入 %d 個數據:", len);
// //建立頭節點
// *L = (LinkList)malloc(sizeof(LNode));
// (*L)->next = NULL;
// //定義一個指向建立結點的指標
// LinkList p = NULL;
// for (int i = 1; i < len; ++i) {
// p = (LinkList)malloc(sizeof(LNode));
// scanf("%d", &p->data);
// p->next = (*L)->next;
// (*L)->next = p;
// }
// printf("\n");
//}
求連結串列的長度
//連結串列長度
int Length(LinkList L) {
int len = 0;
while (L->next != NULL) {
++len;
L = L->next;
}
return len;
}
向動態連結串列中插入結點
//向動態連結串列中插入結點
void InsertList(LinkList* L, int pos, ElemType e) {
//判斷插入位置是否合理
if (pos < 1 || pos > Length(*L) + 1) {
printf("插入位置不合理\n");
return;// exit(0);
}
LinkList adjust = *L;
LinkList insert = (LinkList)malloc(sizeof(LNode));
insert->data = e;
//調整adjust的位置, 準備連線
int i = 0;
while (i++ < pos - 1) {
adjust = adjust->next;
}
//連線右端
insert->next = adjust->next;
//連線左端
adjust->next = insert;
}
從動態連結串列中刪除結點
//從動態連結串列中刪除結點
void DeleteList(LinkList* L, int pos) {
//判斷刪除結點的位置是否合理
if (pos < 1 || pos > Length(*L)) {
printf("刪除結點的位置不合理\n");
return;// exit(0);
}
LinkList adjust = *L;
//調整刪除位置, 準備刪除指定結點
int i = 0;
while (i++ < pos - 1) {
adjust = adjust->next;
}
//儲存要刪除的結點
LinkList deleted = adjust->next;
//連線要刪除結點的兩端結點
adjust->next = deleted->next;
//釋放結點
free(deleted);
}
銷燬一個動態連結串列
//銷燬一個動態連結串列
void DestroyList(LinkList* L) {
LinkList adjust = *L;
while (*L) {
//調整指標始終在頭節點的下一個位置, 用來儲存新的頭節點
adjust = (*L)->next;
//釋放頭節點
free(*L);
//調整新頭節點的位置
*L = adjust;
}
printf("連結串列已銷燬\n");
}
清空一個動態連結串列
//清空一個動態連結串列
void ClearList(LinkList* L) {
LinkList adjust = (*L)->next;
while ((*L)->next) {
//調整指標始終指向被刪除結點的下一個結點, 用來儲存下一個要被刪除的結點
adjust = adjust->next;
//每次釋放頭節點的下一個結點
free((*L)->next);
//更新頭節點的下一個結點(調整指標指向的結點)
(*L)->next = adjust;
}
printf("連結串列已清空\n");
}
判斷連結串列是否為空
//判斷連結串列是否為空
int IsEmpty(LinkList L) {
if (L->next == NULL) {
//printf("連結串列為空\n");
return 1;
}
//printf("連結串列不為空\n");
return 0;
}
獲取動態連結串列上的某個值
//獲取動態連結串列上某個位置上的值
ElemType GetElem(LinkList L, int pos) {
//判斷獲取位置是否合理
if (pos < 1 || pos > Length(L)) {
printf("獲取位置不合理\n");
return 0;// exit(0);
}
LinkList adjust = L;
//調整獲取位置
int i = 0;
while (i++ < pos) {
adjust = adjust->next;
}
//返回獲取值
return adjust->data;
}
在動態連結串列中查詢某個元素
//在動態連結串列中查詢某個元素
void LocateElem(LinkList L, ElemType e) {
LinkList adjust = L->next;
int count = 0;
//遍歷連結串列
while (adjust) {
++count;
if (adjust->data == e) {
printf("找到了該元素, 它是第 %d 個元素\n", count);
return;
}
adjust = adjust->next;
}
printf("沒有找到該元素\n");
}
在動態連結串列中查詢某個元素的前驅
//在動態連結串列中查詢某個元素的前驅
ElemType ProriElem(LinkList L, ElemType cur_e) {
//判斷是否為第一個元素
if (L->next->data == cur_e) {
printf("第一個元素無前驅\n");
return 0;
}
//從第二個元素開始查詢
LinkList adjust = L->next;
while (adjust->next) {
if (adjust->next->data == cur_e) {
return adjust->data;
}
adjust = adjust->next;
}
printf("沒有該元素\n");
return 0;
}
在動態連結串列中查詢某個元素的後繼
//在動態連結串列中找某個元素的後繼
ElemType NextElem(LinkList L, ElemType cur_e) {
//從第一個元素查詢, 最後一個元素要進行判斷
LinkList adjust = L->next;
while (adjust) {
if (adjust->data == cur_e) {
if (adjust->next != NULL) {
return adjust->next->data;
}
printf("最後一個元素沒有後繼\n");
return 0;
}
adjust = adjust->next;
}
printf("沒有該元素\n");
return 0;
}
遍歷連結串列
//遍歷連結串列
void Traverse(LinkList L) {
//判斷連結串列是否為空
if (L->next == NULL) {
printf("連結串列為空\n");
return;
}
while (L->next != NULL) {
printf("%d ", L->next->data);
L = L->next;
}
printf("\n");
}
測試
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <windows.h>
//定義一個動態連結串列
typedef int ElemType;
typedef struct LNode {
ElemType data;
struct LNode* next;
}LNode, *LinkList;
//建立一個動態連結串列
void CreateList(LinkList* L, int len) {
printf("請輸入 %d 個數據:", len);
//建立連結串列的頭節點
*L = (LinkList)malloc(sizeof(LNode));
//定義一個指向尾節點的指標和一個指向建立結點的指標
LinkList rear = *L, p = NULL;
//建立指定大小的空間
for (int i = 1; i < len + 1; ++i) {
p = (LinkList)malloc(sizeof(LNode));
scanf("%d", &p->data);
//尾指標連線新結點
rear->next = p;
//改變尾指標位置
rear = p;
}
//尾指標之後為空
rear->next = NULL;
}
//逆序
//void CreateList(LinkList* L, int len) {
// printf("請輸入 %d 個數據:", len);
// //建立頭節點
// *L = (LinkList)malloc(sizeof(LNode));
// (*L)->next = NULL;
// //定義一個指向建立結點的指標
// LinkList p = NULL;
// for (int i = 1; i < len; ++i) {
// p = (LinkList)malloc(sizeof(LNode));
// scanf("%d", &p->data);
// p->next = (*L)->next;
// (*L)->next = p;
// }
// printf("\n");
//}
//連結串列長度
int Length(LinkList L) {
int len = 0;
while (L->next != NULL) {
++len;
L = L->next;
}
return len;
}
//向動態連結串列中插入結點
void InsertList(LinkList* L, int pos, ElemType e) {
//判斷插入位置是否合理
if (pos < 1 || pos > Length(*L) + 1) {
printf("插入位置不合理\n");
return;// exit(0);
}
LinkList adjust = *L;
LinkList insert = (LinkList)malloc(sizeof(LNode));
insert->data = e;
//調整adjust的位置, 準備連線
int i = 0;
while (i++ < pos - 1) {
adjust = adjust->next;
}
//連線右端
insert->next = adjust->next;
//連線左端
adjust->next = insert;
}
//從動態連結串列中刪除結點
void DeleteList(LinkList* L, int pos) {
//判斷刪除結點的位置是否合理
if (pos < 1 || pos > Length(*L)) {
printf("刪除結點的位置不合理\n");
return;// exit(0);
}
LinkList adjust = *L;
//調整刪除位置, 準備刪除指定結點
int i = 0;
while (i++ < pos - 1) {
adjust = adjust->next;
}
//儲存要刪除的結點
LinkList deleted = adjust->next;
//連線要刪除結點的兩端結點
adjust->next = deleted->next;
//釋放結點
free(deleted);
}
//銷燬一個動態連結串列
void DestroyList(LinkList* L) {
LinkList adjust = *L;
while (*L) {
//調整指標始終在頭節點的下一個位置, 用來儲存新的頭節點
adjust = (*L)->next;
//釋放頭節點
free(*L);
//調整新頭節點的位置
*L = adjust;
}
printf("連結串列已銷燬\n");
}
//清空一個動態連結串列
void ClearList(LinkList* L) {
LinkList adjust = (*L)->next;
while ((*L)->next) {
//調整指標始終指向被刪除結點的下一個結點, 用來儲存下一個要被刪除的結點
adjust = adjust->next;
//每次釋放頭節點的下一個結點
free((*L)->next);
//更新頭節點的下一個結點(調整指標指向的結點)
(*L)->next = adjust;
}
printf("連結串列已清空\n");
}
//判斷連結串列是否為空
int IsEmpty(LinkList L) {
if (L->next == NULL) {
//printf("連結串列為空\n");
return 1;
}
//printf("連結串列不為空\n");
return 0;
}
//獲取動態連結串列上某個位置上的值
ElemType GetElem(LinkList L, int pos) {
//判斷獲取位置是否合理
if (pos < 1 || pos > Length(L)) {
printf("獲取位置不合理\n");
return 0;// exit(0);
}
LinkList adjust = L;
//調整獲取位置
int i = 0;
while (i++ < pos) {
adjust = adjust->next;
}
//返回獲取值
return adjust->data;
}
//在動態連結串列中查詢某個元素
void LocateElem(LinkList L, ElemType e) {
LinkList adjust = L->next;
int count = 0;
//遍歷連結串列
while (adjust) {
++count;
if (adjust->data == e) {
printf("找到了該元素, 它是第 %d 個元素\n", count);
return;
}
adjust = adjust->next;
}
printf("沒有找到該元素\n");
}
//在動態連結串列中查詢某個元素的前驅
ElemType ProriElem(LinkList L, ElemType cur_e) {
//判斷是否為第一個元素
if (L->next->data == cur_e) {
printf("第一個元素無前驅\n");
return 0;
}
//從第二個元素開始查詢
LinkList adjust = L->next;
while (adjust->next) {
if (adjust->next->data == cur_e) {
return adjust->data;
}
adjust = adjust->next;
}
printf("沒有該元素\n");
return 0;
}
//在動態連結串列中找某個元素的後繼
ElemType NextElem(LinkList L, ElemType cur_e) {
//從第一個元素查詢, 最後一個元素要進行判斷
LinkList adjust = L->next;
while (adjust) {
if (adjust->data == cur_e) {
if (adjust->next != NULL) {
return adjust->next->data;
}
printf("最後一個元素沒有後繼\n");
return 0;
}
adjust = adjust->next;
}
printf("沒有該元素\n");
return 0;
}
//遍歷連結串列
void Traverse(LinkList L) {
//判斷連結串列是否為空
if (L->next == NULL) {
printf("連結串列為空\n");
return;
}
while (L->next != NULL) {
printf("%d ", L->next->data);
L = L->next;
}
printf("\n");
}
int main() {
LinkList L1;
CreateList(&L1, 5);
Traverse(L1);
InsertList(&L1, 4, 100);
Traverse(L1);
int value = GetElem(L1, 4);
printf("%d\n", value);
LocateElem(L1, 100);
int prori_e = ProriElem(L1, 100);
printf("%d\n", prori_e);
int next_e = NextElem(L1, 100);
printf("%d\n", next_e);
DeleteList(&L1, 4);
Traverse(L1);
system("pause");
return 0;
}
效果圖