單項循環鏈表及帶頭指針的鏈表

單項循環鏈表及其帶頭指針的鏈表

對于鏈表我們要仔細深入的學習它,為何呢,因為他是我們在后面學習非線性數據結構的基礎,像后面的樹,圖等結構都是由鏈表演變出來的,所以我們這篇博客繼續探究鏈表

帶頭指針的鏈表

我們上篇博客講述了帶頭節點的鏈表

如圖

在這里插入圖片描述

然后演示出了一系列公式化的打法

像什么插入刪除

//找到前置節點p
//插入
new_node->next=p->next;
p->next=new_node;
//刪除
temp=p->next;
p->next=temp->next;
free(temp);

但是我們今天的主角帶頭指針的鏈表,你需要考慮的就多了,公式化的打法已經無法滿足我們了

看圖
在這里插入圖片描述

那我們是否能復刻之前的打法,一套代碼打天下?

肯定不行,你會發現你想要采用頭插法一下就要如下

new_node->next=head;
head=new_node;

當你遇見空的頭指針的時候還要if一下,看起來就麻煩。

那么有簡化一下書寫難度的方法嗎?

有的兄弟,有的。

我們可引入一個dummy節點,這個節點是一個臨時節點,然后將指針的信息臨時傳入進去,而后我們就可以繼續我們的公式化打法處理了,處理完以后再將地址的 值返回。

如圖
在這里插入圖片描述

這樣的好處就又回到了之前的公式化的打法,只要我們注意最后的維護就行了

具體的代碼如下

帶頭指針的鏈表(代碼)

結構定義及其接口


#ifndef CHAINLIST_H
#define CHAIN_LIST_H
//帶頭指針的單向鏈表,維護節點也是node
#include"common.h"//定義鏈表頭結構只保存頭指針
typedef struct {node_t *header;int cout;}ChainList_t;
//表頭放到數據區,放到全局變量
//初始化
void initChainList(ChainList_t *table);
//釋放空間
void destoryChainList(ChainList_t *table);//插入
int insertChainListHeader(ChainList_t* table, Element_t data);//頭插法
int insertChainListpos(ChainList_t* table,int pos, Element_t data);//按位置插入//刪除
int deleteChainListHeader(ChainList_t* table, Element_t data);//打印
void showChainList(const ChainList_t* table);#endif //CHAIN_LIST_H

對操作的具體實現


#include <stdio.h>
#include <stdlib.h>
#include "chainList.h"void initChainList(ChainList_t *table) {table->cout=0;table->header=NULL;
}int insertChainListHeader(ChainList_t *table, Element_t data) {node_t dummy;//定義臨時節點dummy.next=table->header;node_t*p=&dummy;node_t* newnode=(node_t*)malloc(sizeof(node_t));if (newnode==NULL) {return -1;}newnode->data=data;newnode->next=p->next;p->next=newnode;;++table->cout;table->header=dummy.next;return 0;
}int insertChainListpos(ChainList_t *table, int pos, Element_t data) {node_t dummy;dummy.next=table->header;//判斷邊界條件if (data<0||pos>table->cout) {return -1;}//尋找到插入位置node_t *p=&dummy;int node=-1;while (node<pos-1) {p=p->next;node++;}//插入node_t *newnode=(node_t*)malloc(sizeof(node_t));newnode->data=data;newnode->next=p->next;p->next=newnode;++table->cout;table->header=dummy.next;return 0;}
int deleteChainListHeader(ChainList_t *table, Element_t data) {node_t dummy;dummy.next=table->header;node_t* p=&dummy;while (p->next&&p->next->data!=data) {p=p->next;}//判斷是否為空if (p->next==NULL) {printf("No find");return-1;}//刪除node_t*node=p->next;p->next=node->next;free(node);table->cout--;table->header=dummy.next;return 0;}void destoryChainList(ChainList_t *table) {node_t dummy;dummy.next=table->header;node_t* p=&dummy;node_t*node;while (p->next) {node=p->next;p->next=node->next;free(node);table->cout--;}printf("link list number %d",table->cout);}void showChainList(const ChainList_t *table) {node_t* p=table->header;printf("link list number %d\n:",table->cout);while (p) {printf(" %d ",p->data);p=p->next;}printf("\n");}

其實說實話跟之前的帶鏈表的頭指針一樣,只不過需要先申請一個節點對節點做包裝,而后維護一下表頭指針的數據罷了。

我們再來做一下測試

int text2() {ChainList_t stu1;initChainList(&stu1);for (int i=0;i<10;i++) {insertChainListHeader(&stu1,i+100);}insertChainListpos(&stu1,3,300);showChainList(&stu1);destoryChainList(&stu1);}int main() {text2();return 0;
}

這就是對帶頭指針的鏈表的實現

但是如果我們再想提出一個需求,就是鏈表的最后的一個元素要指向第一個元素應該咋整。

這就是引出我們下一個主題

單項循環鏈表

單項循環鏈表

在開始我們的學習之前,我們可以先思考一個對代碼

node_t*p=&header;
while(p->next)
{p=p->next;
}
……node_t*p=&header;
while(p)
{p=p->next
}

你思考就會發現,這兩段代碼是站在不同的角度進行遍歷的,一個是對自己前一個元素進行看的,一個是對自己本身進行看的。

前者更適合插入和刪除,而后者更適合遍歷。

但是,一到循環鏈表這兩段代碼就不管用了,為啥?因為首尾連接了唄。

很自然的,也有兩種循環鏈表的表示方法,一種是帶頭指針的,一種是不帶頭指針的

帶頭指針的

在這里插入圖片描述

不帶頭指針的

在這里插入圖片描述

很正常的我們先實現帶頭指針的

單項循環鏈表代碼

結構定義以及函數接口


#ifndef LINKLOOP_H
#define LINKLOOP_H
typedef int Element;
//節點
typedef struct _loop_node {Element val;struct _loop_node *next;}loopnode;
//頭節點
typedef struct {loopnode head;loopnode *tail;int num;
}LinkLoopList;//結構操作
//初始化
void initLinkLoopList(LinkLoopList *link_loop);
//插入(頭插,尾插)
int insertLinkLoop(LinkLoopList *link_loop, Element val);
int inserLinkLoopRear(LinkLoopList *link_loop, Element val);
//遍歷顯示
void showLinkLoop(const LinkLoopList *link_loop);
//刪除
int deleteLinkLoop(LinkLoopList *link_loop, Element val);
//釋放空間不釋放表頭
void destoryLinkLoopRear(LinkLoopList *link_loop);#endif //LINKLOOP_H

結構操作的實現


#include "linkLoop.h"
#include <stdio.h>
#include <stdlib.h>void initLinkLoopList(LinkLoopList *link_loop) {//循環鏈表一開始就要指向自己link_loop->head.next=link_loop->tail=&link_loop->head;link_loop->num=0;}int insertLinkLoop(LinkLoopList *link_loop, Element val) {//先定義一個新節點loopnode*node=malloc(sizeof(loopnode));if (node==NULL)return -1;node->val=val;node->next=link_loop->head.next;link_loop->head.next=node;//判斷是否維護尾指針if (link_loop->tail==&link_loop->head) {link_loop->tail=node;}link_loop->num++;return 0;}int inserLinkLoopRear(LinkLoopList *link_loop, Element val) {loopnode*node=malloc(sizeof(loopnode));if (node==NULL)return -1;node->val=val;node->next=link_loop->tail->next;link_loop->tail->next=node;link_loop->tail=node;link_loop->num++;return 0;}void showLinkLoop(const LinkLoopList *link_loop) {loopnode*node=link_loop->head.next;while (node!=&link_loop->head) {printf("%d->", node->val);node=node->next;}printf("\n");}int deleteLinkLoop(LinkLoopList *link_loop, Element val) {loopnode*node=&link_loop->head;while (node->next!=&link_loop->head&&node->next->val!=val) {node=node->next;}if (node->next->val==val) {loopnode *tmp=node->next;node->next=tmp->next;free(tmp);link_loop->num--;}else {printf("not found%d\n",val);}return 0;}void destoryLinkLoopRear(LinkLoopList *link_loop) {loopnode*node=link_loop->head.next;while (node!=&link_loop->head) {loopnode *tmp=node;node=node->next;free(tmp);link_loop->num--;}printf("Table %d element\n",link_loop->num);
}

測試函數


#include "linkLoop.h"void text1() {LinkLoopList table;initLinkLoopList(&table);for (int i = 0; i < 10; i++) {inserLinkLoopRear(&table, i+100);}deleteLinkLoop(&table,101);showLinkLoop(&table);destoryLinkLoopRear(&table);}int main() {text1();return 0;
}

結構如下

在這里插入圖片描述

好了這篇博客到這里就結束了,喜歡的點點贊(?′?‵?)I L???????

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/86232.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/86232.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/86232.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

八股文——JAVA基礎:解釋下什么是面向對象?面向對象和面向過程的區別

面向對象和面向過程是編程的不同思想&#xff1a; 面向過程如c語言的編程形式&#xff0c;在編程時定義的是一個方法&#xff0c;然后后續執行只需要關注這個方法的作用&#xff0c;而不會將方法進行抽象&#xff0c;也就是只關注程序執行的過程細節。 面向對象如java&#x…

SuperMap iServer 關閉數據目錄(datacatalog)、地圖打印(webprinting)等服務

背景 漏洞掃描發現有部分低危 web 漏洞&#xff0c;項目又暫未使用數據目錄服務&#xff0c;所以最簡單的方案是直接關閉服務。 查閱文檔發現處理自動化服務可以修改webapps\iserver\WEB-INF\iserver-geoprocessing.xml 的 enable 屬性為 false 關閉&#xff0c;機器學習服務…

PyTorch 張量(Tensors)全面指南:從基礎到實戰

文章目錄 什么是張量&#xff1f;張量初始化方法1. 直接從數據創建2. 從 NumPy 數組轉換3. 基于現有張量創建4. 使用隨機值或常量 張量屬性張量操作設備轉移索引和切片連接張量算術運算單元素張量轉換 原地操作&#xff08;In-place Operations&#xff09;PyTorch 與 NumPy 互…

Maven是什么?

Maven是一個流行的Java項目管理和構建工具&#xff0c;主要用于自動化項目構建、依賴管理和項目文檔生成等工作。以下是對它的簡單介紹&#xff1a; 核心功能 依賴管理&#xff1a;自動管理項目所需的第三方庫&#xff08;如JAR包&#xff09;&#xff0c;通過在配置文件中聲…

etcd教程-快速入門使用(截圖實操)集群搭建 + 原理解釋

大家好&#xff0c;我是此林。 etcd 是一個高可用的鍵值對存儲系統&#xff0c;常用于分布式系統中保存配置、服務發現和協調信息。它是 CNCF 旗下的項目之一&#xff0c;也是 Kubernetes 的核心組件之一&#xff0c;用來存儲集群狀態。 可以說&#xff0c;云原生場景下經常使…

OpenSSL 混合加密

openssl 中文網&#xff1a; https://www.openssl.net.cn/ 目錄 對稱加密特點常見算法案例&#xff08;使用 AES&#xff09; 非對稱加密特點常見算法案例&#xff08;使用 RSA&#xff09; 混合加密場景加密&#xff08;使用 AES&#xff09;解密 總結 對稱加密 特點 加密和解…

AI驅動的DevOps運維與云服務部署自動化

引言 當前&#xff0c;云計算和DevOps實踐讓開發者能夠管理成百上千臺服務器和容器&#xff0c;但隨之而來的運維復雜度也急劇提升。運維工程師經常需要部署多環境應用、維護大規模云主機、排查集群故障等任務。這些任務不僅涉及繁瑣的腳本編寫和命令行操作&#xff0c;還需要對…

Spring Boot動態數據源切換:優雅實現多數據源管理

在復雜的企業應用中&#xff0c;多數據源管理是常見需求。本文將介紹如何基于Spring Boot實現優雅的動態數據源切換方案&#xff0c;通過自定義注解和AOP實現透明化切換。 核心設計思路 通過三層結構實現數據源動態路由&#xff1a; 1. 注解層&#xff1a;聲明式標記數據源 2…

如何挑選一款1588PTP時鐘同步服務器?

在當今數字化程度極高的時代&#xff0c;高精度時間同步對于眾多關鍵領域的高效、穩定運行起著決定性作用。PTP&#xff08;精確時間協議&#xff09;時鐘作為實現高精度時間同步的核心設備&#xff0c;其性能優劣直接關乎系統整體表現。挑選一款合適的 ptp網絡同步時鐘&#x…

Harmony狀態管理 @Local和@Param

深入理解ArkUI中的Param與Local裝飾器 引言 在ArkUI的狀態管理系統中&#xff0c;Param和Local是兩個核心裝飾器&#xff0c;它們分別用于處理組件間的數據傳遞和組件內部狀態管理。本文將詳細介紹這兩個裝飾器的使用場景、特性差異以及最佳實踐。 Param裝飾器&#xff1a;組…

物聯網攝像頭模塊的應用場景

一、智慧城市治理 ?智能交通優化? ?動態信號控制?&#xff1a;杭州部署20萬物聯網攝像頭&#xff0c;實時分析車流密度并聯動1200個紅綠燈&#xff0c;早高峰通行效率提升40%。 ?違規行為識別?&#xff1a;搭載GB/T28181協議的攝像頭AI抓拍交通違章&#xff0c;車牌識…

k8s Ingress、Service配置各樣例大全

目錄 壹、k8s Ingress 樣例大全&#x1f527; 一、基礎路由與 TLS 終止&#x1f504; 二、高級路由控制1. **URL 重寫**&#xff08;適用后端服務路徑與入口路徑不一致&#xff09;2. **多路徑路由到不同服務** &#x1f6a6; 三、流量治理策略1. **金絲雀發布&#xff08;灰度…

領域驅動設計(DDD)【10】之DDD戰術模式:工廠模式與表意接口模式

文章目錄 引言&#xff1a;DDD戰術模式的重要性一、DDD中的工廠模式1.1 工廠模式的核心概念1.2 工廠模式的三種實現方式1.2.1 簡單工廠方法1.2.2 工廠類1.2.3 抽象工廠模式 1.3 工廠模式的適用場景1.4 實際案例&#xff1a;電商訂單系統 二、表意接口模式2.1 表意接口2.2 表意接…

鴻蒙ArkTS---登錄邏輯,數據持久化,ArkUI,網絡請求等基礎內容記錄

該內容是在【博學谷】學習過程中的代碼記錄&#xff0c;如有任何問題請與作者聯系。 也歡迎同在學習鴻蒙開發的小伙伴的留言&#xff0c;一同學習&#xff0c;一同進步。 功能實現&#xff08;只記錄代碼&#xff0c;沒有相關配置&#xff0c;跑不起來&#xff09;&#xff…

沒有公網ip可以實現跨網p2p互通嗎?內網讓公網直連訪問常用工具

沒有公網IP的情況下仍然可以實現P2P通信&#xff0c;但需要借助NAT穿透技術或類似nat123同端口映射等第三方工具實現內網穿透?。???? 一、什么是P2P通信&#xff1f; P2P網絡&#xff08;Peer-to-Peer Network&#xff09;是一種去中心化的網絡架構&#xff0c;其中每個…

云服務器安裝寶塔面板(BT Panel)

安裝寶塔面板&#xff08;BT Panel&#xff09;是很多服務器管理員常用的操作&#xff0c;尤其適合用于管理網站、數據庫、FTP等。以下是基于 Linux 系統&#xff08;推薦 CentOS 或 Ubuntu&#xff09;的寶塔面板安裝步驟。 安裝前準備 云服務器一臺 可以訂購服務器 海外云主…

mongoose解析http字段值

最近在使用mongoose開發嵌入式web后端時&#xff0c;會遇到要解析js前端發送過來的http消息&#xff0c;比如傳遞用戶名&#xff0c;密碼過來&#xff0c;后端要解析出來并判斷是否登錄成功。 前端http有兩種組裝字段的方式。 第一種是 $.ajax({url: /upgradePackage,method: P…

高德地圖地址解析獲取經緯度失敗原因JSAPI

高德地圖地址解析獲取經緯度失敗原因JSAPI 地圖加載的時候老是報異常碼&#xff0c;地圖是可以加載出來的&#xff0c;但是在地圖上的操作老是有異常碼&#xff0c;找了好久不知道什么問題&#xff0c;異常碼會報兩種&#xff0c;一種是說什么key的問題&#xff0c;但是我當時…

極速JavaScript:全面性能優化實戰指南

在現代Web開發中&#xff0c;JavaScript性能直接影響用戶體驗。一個優化良好的應用能帶來更流暢的交互、更快的加載速度和更低的資源消耗。本文將深入探討實用的JavaScript性能優化技術&#xff0c;幫助您打造高性能Web應用。 一、性能瓶頸分析與診斷工具 性能問題的常見來源&…

【開源模型】高考數學139分!小米MiMo開源模型:7B參數突出重圍

小米 MiMo&#xff1a;7 B 參數撬動推理巔峰&#xff0c;開源模型的技術突圍 70 億參數超越 320 億對手&#xff0c;高考數學 139 分的背后是訓練策略的全面革新。 2025 年 4 月 30 日&#xff0c;小米開源的首個推理大模型 Xiaomi MiMo-7 B 橫空出世&#xff0c;以??僅 7 B …