網站首頁 編程語言 正文
(?′?`?) 單鏈表
前言
上篇順序表結尾了解了順序表的諸多缺點,鏈表的特性很好的解決了這些問題,本期我們來認識單鏈表。
一、鏈表是什么
鏈表是一種物理存儲結構上非連續、非順序的存儲結構,數據元素的邏輯順序是通過鏈表中的指針鏈接依次實現的。
- 由圖,鏈式結構在邏輯上是連續的,但是物理上不一定連續
- 顯示中結點一般是從堆上申請出來的
- 從堆上申請的空間,是按照一定的策略劃分的,兩次申請的空間,可能連續,可能不連續,見順序表
鏈表的分類
鏈表也可以分為很多種
1. 單向或者雙向
2. 帶頭或者不帶頭
3. 循環或非循環
我們最常用的還是無頭單向非循環鏈表和帶頭雙向循環鏈表 本篇我們實現無頭單向非循環鏈表增刪查改
二、鏈表的實現
基本結點結構
typedef int SLTDateType; typedef struct SListNode { SLTDateType data; struct SListNode* next; }SListNode;
頭文件
//llist.h #pragma once #include <stdio.h> #include <assert.h> #include <stdlib.h> #include <string.h> typedef int SLTDateType; typedef struct SListNode { SLTDateType data; struct SListNode* next; }SListNode; // 動態申請一個節點 SListNode* BuySListNode(SLTDateType x); // 單鏈表打印 void SListPrint(SListNode* plist); // 單鏈表尾插 void SListPushBack(SListNode** pplist, SLTDateType x); // 單鏈表的頭插 void SListPushFront(SListNode** pplist, SLTDateType x); // 單鏈表的尾刪 void SListPopBack(SListNode** pplist); // 單鏈表頭刪 void SListPopFront(SListNode** pplist); // 單鏈表查找 SListNode* SListFind(SListNode* plist, SLTDateType x); // 單鏈表在pos位置之后插入x // 分析思考為什么不在pos位置之前插入? void SListInsertAfter(SListNode* pos, SLTDateType x); // 單鏈表刪除pos位置之后的值 // 分析思考為什么不刪除pos位置? void SListEraseAfter(SListNode* pos); // 單鏈表的銷毀 void SListDestory(SListNode* plist);
動態申請一個節點
// 動態申請一個節點 SListNode* BuySListNode(SLTDateType x) { SListNode* newnode = (SListNode*)malloc(sizeof(SListNode)); if (newnode == NULL)//申請失敗 { printf("malloc fail\n"); exit(-1); } else { newnode->data = x; newnode->next = NULL; } return newnode; }
單鏈表打印
鏈表單個結點中,data存儲數據,next存儲下一個結點的地址,可以通過next訪問下一個結點
// 單鏈表打印 void SListPrint(SListNode* plist) { SListNode* cur = plist; while (cur != NULL) { printf("%d->", cur->data); cur = cur->next;//訪問下一個結點 } printf("NULL\n"); }
單鏈表尾插
這里傳入了頭結點的地址的指針,是因為有可能要改變頭結點的情況,傳址調用幻術,如果只傳入*plist,相當于只改變形參,實參不會有實際改變,通過pplist可以解決這個問題
// 單鏈表尾插 void SListPushBack(SListNode** pplist, SLTDateType x) { SListNode* newnode = BuySListNode(x); if (*pplist == NULL)//空鏈表 { *pplist = newnode; } else { SListNode* tail = *pplist;//遍歷至最后插入 while (tail->next != NULL) { tail = tail->next; } tail->next = newnode; } }
單鏈表的尾刪
一前一后遍歷,找到空后直接free(tail),將prev->next置空即可
// 單鏈表的尾刪 void SListPopBack(SListNode** pplist) { assert(pplist); if (*pplist == NULL)//空鏈表,無需刪除 { return; } else { SListNode* prev = NULL; SListNode* tail = *pplist; { while (tail->next != NULL) { prev = tail; tail = tail->next; } free(tail); tail = NULL; prev->next = NULL; } } }
單鏈表的頭插
有點繞,要多想想
// 單鏈表的頭插 void SListPushFront(SListNode** pplist, SLTDateType x) { assert(pplist); SListNode* newnode = BuySListNode(x); newnode->next = *pplist; *pplist = newnode; }
單鏈表頭刪
比較簡單
// 單鏈表頭刪 void SListPopFront(SListNode** pplist) { assert(pplist); if (*pplist == NULL)//鏈表為空 { return; } else { SListNode* next = (*pplist)->next; free(*pplist); *pplist = next; } }
// 單鏈表查找 遍歷即可 SListNode* SListFind(SListNode* plist, SLTDateType x) { SListNode* cur = plist; while (cur != NULL) { if (cur->data = x) { return cur; } cur = cur->next; } retuen NULL; }
*單鏈表在pos位置之后插入x
為什么不在pos之前插入,由于我們是單向鏈表,需要從頭遍歷查找pos,如果在pos之前插入,找到pos還需找到pos之前的地址,對所傳參數不友好,所以我們一般在后插入
//單鏈表在pos位置之后插入x void SListInsertAfter(SListNode* pos, SLTDateType x) { assert(pos); SListNode* newnode = BuySListNode(x); newnode->next = pos->next; pos->next = newnode; }
單鏈表刪除pos位置之后的值 為什么不刪除pos位置,同上,在邏輯上和傳參不友好.
// 單鏈表刪除pos位置之后的值 void SListEraseAfter(SListNode* pos) { assert(pos); SListNode* next = pos->next; if (next) { pos->next = next->next; free(next); next = NULL; } }
單鏈表的銷毀 鏈表不像順序表連續刪頭就可以,由于鏈表是一個一個分散的結點,需要逐一刪除
// 單鏈表的銷毀 void SListDestory(SListNode** pplist) { assert(*pplist); SListNode* cur = *pplist; while (cur) { SListNode* next = cur->next; free(cur); cur = next; } *pplist = NULL; }
總結
鏈表相比但鏈表難度提升不少,對c的掌握也變大,不清晰的地方要多想多畫圖。還請斧正
原文鏈接:https://blog.csdn.net/qq_62852431/article/details/123542116
相關推薦
- 2022-10-16 go?swagger生成接口文檔使用教程_Golang
- 2022-07-10 初中級前端程序員必用且夠用的git命令同時推送到github/gitee及三種常用場景
- 2023-01-08 Python創建二維數組與初始化的實踐舉例_python
- 2022-10-30 Python?Pandas學習之series的二元運算詳解_python
- 2023-10-31 springboot 線程池參數解釋
- 2022-05-06 Python學習之模塊化程序設計示例詳解_python
- 2023-07-16 springboot動態端口
- 2022-05-10 用async修飾的函數是異步函數嗎?
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支