網(wǎng)站首頁 編程語言 正文
前言
鏈表是指由一系列儲(chǔ)存在非連續(xù)儲(chǔ)存空間 結(jié)點(diǎn)組成的儲(chǔ)存結(jié)構(gòu)。每個(gè)結(jié)點(diǎn)由兩部分組成:一是儲(chǔ)存元素的數(shù)據(jù)域,一是儲(chǔ)存下一個(gè)節(jié)點(diǎn)地址的指針域。用數(shù)組模擬鏈表可以十分清晰明了地理解這一定義。
在這里,我們簡單地介紹一下單鏈表和雙鏈表兩種鏈表以及用數(shù)組模擬實(shí)現(xiàn)它們的方式。
1.單鏈表
單鏈表是指針方向單向的鏈表,即a結(jié)點(diǎn)的指針域儲(chǔ)存著b結(jié)點(diǎn)的地址,而b結(jié)點(diǎn)的指針域內(nèi)沒有儲(chǔ)存a結(jié)點(diǎn)的地址。在訪問時(shí),可以由a到b訪問,而不能由b到a訪問。
如圖可以清晰地看到,各個(gè)結(jié)點(diǎn)的指向都是單向的。
Q: 那么,如何用數(shù)組來實(shí)現(xiàn)它呢?
A: 方法如下
在k結(jié)點(diǎn)右側(cè)插入元素x。先將x賦值給該節(jié)點(diǎn)的數(shù)據(jù)域(e[idx]),然后將k結(jié)點(diǎn)的指針域賦值給該結(jié)點(diǎn)的指針域,最后將k結(jié)點(diǎn)的指針域儲(chǔ)存的地址改為該節(jié)點(diǎn)的地址。
void add(int k, int x) { e[idx] = x; ne[idx] = ne[k]; ne[k] = idx++; }
刪除k結(jié)點(diǎn)指向的結(jié)點(diǎn)。這里所指的刪除,是將k的指向改為該結(jié)點(diǎn)的指向。原本為a -> b -> c,改為a -> c,b結(jié)點(diǎn)依然存在,只是沒有其他結(jié)點(diǎn)指向它,也就無法通過鏈表訪問它,我們認(rèn)為它就再鏈表上被刪除了。
void remove(int k) { ne[k] = ne[ne[k]]; }
讀取鏈表。讀取鏈表只用注意一點(diǎn),在用單指針掃描時(shí)不是將指針位置右移,而是將指針移動(dòng)到該結(jié)點(diǎn)指向的位置。
for (int i = head; i != -1; i = ne[i]) cout << e[i] << ' '; cout << endl;
主要的操作就是如此,下邊看看完整代碼:
這是較為經(jīng)典的寫法,我個(gè)人認(rèn)為有些麻煩,head不必單獨(dú)拿出來寫一個(gè)函數(shù)。但是有助于理解。
#include<iostream> using namespace std; const int M = 1e5 + 10; int m, k, x, idx, head; int e[M], ne[M]; void init() { head = -1, idx = 0; } void add_head(int x) { e[idx] = x; ne[idx] = head; head = idx++; } void remove(int k) { ne[k] = ne[ne[k]]; } void add(int k, int x) { e[idx] = x; ne[idx] = ne[k]; ne[k] = idx++; } int main() { init(); cin >> m; while (m--) { char op; cin >> op; if (op == 'H') { cin >> x; add_head(x); } else if (op == 'D') { cin >> k; if (!k) head = ne[head]; remove(k - 1); } else { cin >> k >> x; add(k - 1, x); } } for (int i = head; i != -1; i = ne[i]) cout << e[i] << ' '; cout << endl; return 0; }
這種寫法稍微簡便一些,用a[0]替代head。
#include<iostream> using namespace std; const int M = 1e5 + 10; int m, k, x, idx, head; int e[M], ne[M]; void init() { ne[0] = -1, idx = 1; } void remove(int k) { ne[k] = ne[ne[k]]; } void add(int k, int x) { e[idx] = x; ne[idx] = ne[k]; ne[k] = idx++; } int main() { init(); cin >> m; while (m--) { char op; cin >> op; if (op == 'H') { cin >> x; add(0, x); } else if (op == 'D') { cin >> k; if (!k) head = ne[head]; remove(k); } else { cin >> k >> x; add(k, x); } } for (int i = ne[0]; i != -1; i = ne[i]) cout << e[i] << ' '; cout << endl; return 0; }
2.雙鏈表
雙鏈表顧名思義就是指針方向雙向的鏈表。
可以看到除了頭尾他們的指針都是雙向的。
它的實(shí)現(xiàn)方法如下:
創(chuàng)建開始和結(jié)束結(jié)點(diǎn)。0表示開始,1表示結(jié)束,互相指向,在插入時(shí)直接往中間插入即可。
void init() { r[0] = 1, l[1] = 0; idx = 2; }
插入結(jié)點(diǎn)。雙鏈表插入結(jié)點(diǎn)的方法與單鏈表相同,但是操作要稍微復(fù)雜一些,這是在k結(jié)點(diǎn)右邊插入一結(jié)點(diǎn)的代碼。它要顧及結(jié)點(diǎn)左右的結(jié)點(diǎn)指向,對于兩邊都要操作。面臨在k結(jié)點(diǎn)左邊插入一結(jié)點(diǎn)時(shí),不必單獨(dú)在寫一個(gè)函數(shù),而改成在l[k]結(jié)點(diǎn)的右邊插入一個(gè)結(jié)點(diǎn)。
void add(int k, int x) { a[idx] = x; r[idx] = r[k], l[idx] = l[r[k]]; l[r[k]] = idx, r[k] = idx; idx++; }
刪除節(jié)點(diǎn)。刪除結(jié)點(diǎn)與插入結(jié)點(diǎn)同理,我就不多贅述了。
void remove(int k) { r[l[k]] = r[k]; l[r[k]] = l[k]; }
輸出鏈表。可以選擇輸出方向,這里是從左往右輸出。
for (int i = r[0]; i != 1; i = r[i])cout << a[i] << ' '; cout << endl;
以下是完整代碼:
#include<iostream> using namespace std; const int N = 1e5 + 10; int a[N], l[N], r[N]; int idx; int m; void init() { r[0] = 1, l[1] = 0; idx = 2; } void add(int k, int x) { a[idx] = x; r[idx] = r[k], l[idx] = l[r[k]]; l[r[k]] = idx, r[k] = idx; idx++; } void remove(int k) { r[l[k]] = r[k]; l[r[k]] = l[k]; } int main() { init(); cin >> m; while (m--) { int k, x; string op; cin >> op; if (op == "L") { cin >> x; add(0, x); } else if (op == "R") { cin >> x; add(l[1], x); } else if (op == "D") { cin >> k; remove(k + 1); } else if (op == "IL") { cin >> k >> x; add(l[k + 1], x); } else if (op == "IR") { cin >> k >> x; add(k + 1, x); } } for (int i = r[0]; i != 1; i = r[i])cout << a[i] << ' '; cout << endl; return 0; }
總結(jié)
原文鏈接:https://blog.csdn.net/Kicamon/article/details/122432389
相關(guān)推薦
- 2022-12-05 單步調(diào)試?step?into/step?out/step?over?區(qū)別說明_python
- 2022-11-20 C++遞歸算法處理島嶼問題詳解_C 語言
- 2022-10-13 pytorch和tensorflow計(jì)算Flops和params的詳細(xì)過程_python
- 2022-04-03 基于Docker實(shí)現(xiàn)Redis主從+哨兵搭建的示例實(shí)踐_docker
- 2022-12-09 C++筆記-設(shè)置cout輸出數(shù)據(jù)的寬度和填充方式_C 語言
- 2022-02-25 DevTools failed to load SourceMap 警告處理方法
- 2022-10-27 Apache?Hive?通用調(diào)優(yōu)featch抓取機(jī)制?mr本地模式_Linux
- 2023-01-28 一文詳解Go語言fmt標(biāo)準(zhǔn)庫的常用占位符使用_Golang
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支