C語言數據結構(4)單鏈表專題2.單鏈表的應用

1. 鏈表經典算法——OJ題目

1.1 單鏈表相關經典算法OJ題1:移除鏈表元素

1.2 單鏈表相關經典算法OJ題2:反轉鏈表

1.3 單鏈表相關經典算法OJ題3:合并兩個有序鏈表

1.4 單鏈表相關經典算法OJ題4:鏈表的中間結點

1.5 循環鏈表經典應用-環形鏈表的約瑟夫問題

著名的Josephus問題

據說著名猶太歷史學家 Josephus有過以下的故事:在羅馬人占領喬塔帕特后,39 個猶太人與Josephus及他的朋友躲到一個洞中,39個猶太人決定寧愿死也不要被人抓到,于是決定了一個自殺方式,41個人排成一個圓圈,由第1個人開始報數,每報數到第3人該人就必須自殺,然后再由下一個重新報數,直到所有人都自殺身亡為止。

然而Josephus 和他的朋友并不想遵從,Josephus要他的朋友先假裝遵從,他將朋友與自己安排在 第16個與第31個位置,于是逃過了這場死亡游戲。

1.6 單鏈表相關經典算法OJ題5:分割鏈表


1.1 移除鏈表元素

沒要求在原地完成移除元素操作。

新鏈表不創建新的空間,只需要創建兩個頭尾指針,輔助完成鏈表內部結點指向的更改。

1.2 反轉鏈表

思路1:遍歷+頭插

思路2:三指針

傳遞給head的實參在函數調用結束后,依然指向Node1——傳值調用。

需要用在主調函數內使用主調函數內的head,接收函數調用的返回值。

1.3 合并兩個有序鏈表

思路1:將L2插入到L1中,過程中的控制比較復雜。

思路2:創建新鏈表L3,誰小誰尾插。

1.4 鏈表的中間結點

雙指針法:源宿指針、快慢指針、……

1.5 環形鏈表的約瑟夫問題

圖解分析。

1.5.1 新建結點

typedef struct ListNode ListNode;
ListNode* BuyNode(int x){ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));//可寫可不寫,一般不會申請失敗//if(newNode == NULL){//    exit(1);//}newNode->val = x;newNode->next = NULL;return newNode;
}

1.5.2 新建環形鏈表

ListNode* createList(int n){ListNode* phead = BuyNode(1);ListNode* ptail = phead;for (int i = 2; i <= n; i++){ptail->next = BuyNode(i);ptail = ptail->next;}//鏈表要首尾相連,使其循環起來ptail->next = phead;return phead;
}

1.5.3 約瑟夫問題

int ysf(int n, int m ) {//創建不帶頭單向循環鏈表ListNode* head = createList(n);ListNode* pcur = head;ListNode* prev = NULL;//count==m就刪除當前結點,并重置count,繼續遍歷遞增int count = 1;                  //一開始pcur指向head,count就應該數了1//逢m刪除節點while (pcur->next != pcur) {    //循環條件:不止一個結點if(count == m){//刪除當前節點pcur,prev->next = pcur->next;free(pcur);//刪除pcur節點之后,要讓pcur走到新的位置,count置為初始值pcur = prev->next;count = 1;}else{//pcur往后走prev = pcur;pcur = pcur->next;count++;}}//此時pcur結點就是幸存下來的唯一的一個節點return pcur->val;
}

提交代碼。

但是自測運行。

問題:若m = 1時,第一次進循環就要刪除pcur,而此時prev還是為空?

解決辦法: createList方法不返回頭結點,而是返回尾結點。既能知道第一個節點的前驅節點,也能夠通過尾結點找到第一個節點。

1.6 分割鏈表

思路1:創建一個新鏈表,將原鏈表中小于x的結點頭插,大于等于x的結點尾插。

思路2:創建兩個新鏈表,一個大鏈表,一個小鏈表,遍歷插入完后,小鏈表尾插大鏈表。

數組的分割可以從兩邊向中間遍歷,左下標遇到大于等于x的就停下,右下標遇到小于x的就停下,然后交換數據,繼續往中間走,while(left <?right)。

2. 基于單鏈表再實現通訊錄項目

2.1 單鏈表頭文件

//SList.h
//
// Created by mm on 2023/6/13.
//
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include"contact.h"
typedef struct PersonInfo SLTDataType;
//typedef int SLTDataType;void SLTPrint(SLTNode* phead);
//頭部插?刪除/尾部插?刪除
void SLTPushBack(SLTNode** pphead, SLTDataType x);
void SLTPushFront(SLTNode** pphead, SLTDataType x);
void SLTPopBack(SLTNode** pphead);
void SLTPopFront(SLTNode** pphead);
//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
//在指定位置之前插?數據
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//刪除pos節點
void SLTErase(SLTNode** pphead, SLTNode* pos);
//在指定位置之后插?數據
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
//刪除pos之后的節點
void SLTEraseAfter(SLTNode* pos);
//銷毀鏈表
void SListDesTroy(SLTNode** pphead);

2.2 通訊錄頭文件


//contact.h
#pragma once
#define NAME_MAX 100
#define SEX_MAX 4
#define TEL_MAX 11
#define ADDR_MAX 100
//前置聲明
typedef struct SListNode contact;
//用戶數據
typedef struct PersonInfo
{char name[NAME_MAX];char sex[SEX_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];
}PeoInfo;//初始化通訊錄
void InitContact(contact** con);
//添加通訊錄數據
void AddContact(contact** con);
//刪除通訊錄數據
void DelContact(contact** con);
//展示通訊錄數據
void ShowContact(contact* con);
//查找通訊錄數據
void FindContact(contact* con);
//修改通訊錄數據
void ModifyContact(contact** con);
//銷毀通訊錄數據
void DestroyContact(contact** con);

2.3 通訊錄源文件


//contact.c
#define _CRT_SECURE_NO_WARNINGS
#include"contact.h"
#include"SList.h"void LoadContact(contact** con) {FILE* pf = fopen("contact.txt", "rb");if (pf == NULL) {perror("fopen error!\n");return;}//循環讀取文件數據PeoInfo info;while (fread(&info, sizeof(info), 1, pf)){SLTPushBack(con, info);}printf("歷史數據導入通訊錄成功!\n");
}void InitContact(contact** con) {LoadContact(con);
}void AddContact(contact** con) {PeoInfo info;printf("請輸入姓名:\n");scanf("%s", &info.name);printf("請輸入性別:\n");scanf("%s", &info.sex);printf("請輸入年齡:\n");scanf("%d", &info.age);printf("請輸入聯系電話:\n");scanf("%s", &info.tel);printf("請輸入地址:\n");scanf("%s", &info.addr);SLTPushBack(con, info);printf("插入成功!\n");
}contact* FindByName(contact* con, char name[]) {contact* cur = con;while (cur){if (strcmp(cur->data.name, name) == 0) {return cur;}cur = cur->next;}return NULL;
}void DelContact(contact** con) {char name[NAME_MAX];printf("請輸?要刪除的用戶姓名:\n");scanf("%s", name);contact* pos = FindByName(*con, name);if (pos == NULL) {printf("要刪除的用戶不存在,刪除失敗!\n");return;}SLTErase(con, pos);printf("刪除成功!\n");
}void ShowContact(contact* con) {printf("%-10s %-4s %-4s %15s %-20s\n", "姓名", "性別", "年齡", "聯系電話",contact* cur = con;while (cur){printf("%-10s %-4s %-4d %15s %-20s\n",cur->data.name,cur->data.sex,cur->data.age,cur->data.tel,cur->data.addr);cur = cur->next;}
}void FindContact(contact* con) {char name[NAME_MAX];printf("請輸?要查找的用戶姓名:\n");scanf("%s", name);contact* pos = FindByName(con, name);if (pos == NULL) {printf("要查找的用戶不存在,查找失敗!\n");return;}printf("查找成功!\n");printf("%-10s %-4s %-4d %15s %-20s\n",pos->data.name,pos->data.sex,pos->data.age,pos->data.tel,pos->data.addr);
}void ModifyContact(contact** con) {char name[NAME_MAX];printf("請輸?要修改的用戶名稱:\n");scanf("%s", &name);contact* pos = FindByName(*con, name);if (pos == NULL) {printf("要查找的用戶不存在,修改失敗!\n");return;}printf("請輸入要修改的姓名:\n");scanf("%s", pos->data.name);printf("請輸入要修改的性別:\n");scanf("%s", pos->data.sex);printf("請輸入要修改的年齡:\n");scanf("%d", &pos->data.age);printf("請輸入要修改的聯系電話:\n");scanf("%s", pos->data.tel);printf("請輸入要修改的地址:\n");scanf("%s", pos->data.addr);printf("修改成功!\n");
}void SaveContact(contact* con) {FILE* pf = fopen("contact.txt", "wb");if (pf == NULL) {perror("fopen error!\n");return;}//將通訊錄數據寫入文件contact* cur = con;while (cur){fwrite(&(cur->data), sizeof(cur->data), 1, pf);cur = cur->next;}printf("通訊錄數據保存成功!\n");
}void DestroyContact(contact** con) {SaveContact(*con);SListDesTroy(con);
}

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

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

相關文章

Shell 腳本發送信號給 C 應用程序,讓 C 應用程序回收線程資源后自行退出。

下面分別給出一個 Shell 腳本和 C 程序的例子&#xff0c;實現通過 Shell 腳本發送信號給 C 應用程序&#xff0c;讓 C 應用程序回收線程資源后自行退出。原理在 Linux 系統中&#xff0c;我們可以使用信號機制來實現進程間的通信。Shell 腳本可以使用 kill 命令向指定的進程發…

C++入門自學Day6-- STL簡介(初識)

往期內容回顧 C模版 C/C內存管理&#xff08;初識&#xff09; C/C內存管理&#xff08;續&#xff09; STL簡介&#xff1a; STL 是 C 標準庫的重要組成部分&#xff0c;是一個通用程序設計的模板庫&#xff0c;用于數據結構和算法的復用。它極大地提升了代碼效率、可靠性…

從零開始搞定類與對象(中)

運算符重載1.當運算符被用于類類型的對象時&#xff0c;C語言允許我們通過運算符重載的形式指定新的含義。C規定類類型對象使用運算符時&#xff0c;必須轉換成調用對應運算符重載&#xff0c;若沒有對應的運算符重載&#xff0c;則會編譯報錯。2. 運算符重載是具有特殊名字的函…

SpringMVC實戰指南:從環境搭建到功能實現全解析

第一章&#xff1a;SpringMVC環境搭建與基礎配置1.1 Maven依賴配置在Maven項目中&#xff0c;SpringMVC的依賴配置是開發的第一步。根據Spring官方推薦&#xff0c;以下是SpringMVC 5.3.x版本的Maven依賴配置&#xff1a;<dependencies><!-- Spring MVC核心依賴 -->…

Repo 與 manifest

Manifest&#xff1a;它本身就是一個 git 倉庫&#xff0c;其中存放的都是包含倉庫和子倉庫信息的XML文件。這些文件全部由開發者或者維護者手動配置并自己上傳到 git 倉庫。另外&#xff1a;Manifest 中的倉庫之間的依賴關系 repo 也并不關心。所以它們可以是同級的也可以是包…

深入淺出 RabbitMQ:簡單隊列實戰指南

大家好&#xff0c;我是工藤學編程 &#x1f989;一個正在努力學習的小博主&#xff0c;期待你的關注實戰代碼系列最新文章&#x1f609;C實現圖書管理系統&#xff08;Qt C GUI界面版&#xff09;SpringBoot實戰系列&#x1f437;【SpringBoot實戰系列】SpringBoot3.X 整合 Mi…

Ubuntu22-Qt Creator-fcitx-中文輸入

fcitx在ubuntu系統中路徑 /usr/lib/x86_64-linux-gnu/qt5/plugins/platforminputcontexts/ /usr/lib/x86_64-linux-gnu/qt6/plugins/platforminputcontexts/ fcitx-qt5-1.2.7 編譯 下載鏈接:https://github.com/fcitx/fcitx-qt5/archive/refs/tags/1.2.7.zip Qt版本:Qt C…

【Java基礎|第十三篇】面向對象基礎(三)——繼承(一)繼承的理解,實現,特點……

&#xff08;四&#xff09;面向對象&#xff1a; 5、繼承&#xff1a; &#xff08;1&#xff09;理解&#xff1a; 概念&#xff1a; 繼承是面向對象的三大特征之一 繼承是類與類之間關系的一種&#xff08;是父類與子類的關系&#xff09; 使用場景&#xff1a; 一個類與另…

QGIS綠色版吉林一號切片體驗版插件(Jilin1Tiles)更新

吉林一號更新2024年圖源了但吉林一號切片體驗版插件&#xff08;Jilin1Tiles&#xff09;還沒有更新&#xff0c;我修改了一下代碼&#xff0c;直接集成到QGIS綠色版中。如下&#xff1a;注意&#xff1a;第一次使用的時候需要選中啟用一下插件&#xff1a;需要使用的可以直接下…

git操作命令和golang編譯腳本

git子模塊信息處理命令git init submodule git submodule updategit取消合并 git merge --abort git reset --hard HEAD{1}bat文件生成二進制set GOOSlinux set GOARCHamd64 go env -w GOFLAGS-modvendor go build -ldflags "-w -s" -ohallapiset GOOSlinux set GOAR…

通往L4之路:構建自我進化的智能駕駛決策大腦

摘要&#xff1a; 本文旨在提出一個超越當前主流“感知-預測-規劃”分離式架構的下一代自動駕駛決策系統方案。面對自動駕駛領域最核心的“長尾場景”難題&#xff0c;本文借鑒并升華了一套源于復雜策略制定的決策智能框架&#xff0c;通過構建動態駕駛世界模型&#xff08;Dyn…

AI編程助手:終結996的新希望

引言程序員工作現狀與“996”現象的普遍性AI技術快速發展對編程效率的潛在影響核心問題&#xff1a;AI IDE與AI輔助編程能否改變傳統開發模式AI IDE與AI輔助編程的核心技術AI IDE的定義與功能&#xff08;代碼補全、錯誤檢測、自動重構等&#xff09;AI輔助編程工具&#xff08…

Anthropic 禁止 OpenAI 訪問 Claude API:商業競爭與行業規范的沖突

Anthropic 禁止 OpenAI 訪問 Claude API&#xff1a;商業競爭與行業規范的沖突 文章來源&#xff1a;Poixe AI 本周&#xff0c;美國 AI 公司 Anthropic 宣布禁止 OpenAI 通過 API 訪問其 Claude 系列大模型。這一舉動引發了行業對"友好基準測試"與商業競爭邊界的熱…

區塊鏈 + 物聯網落地案例:供應鏈溯源系統開發全記錄

本文詳細記錄了區塊鏈與物聯網技術融合的供應鏈溯源系統開發全流程。從項目背景出發&#xff0c;闡述傳統供應鏈溯源痛點&#xff0c;介紹系統開發的技術架構設計&#xff0c;包括物聯網數據采集層、區塊鏈數據存儲層等核心模塊&#xff0c;詳解硬件選型、智能合約編寫、數據上…

Windows環境下Intel Fortran如何安裝配置NetCDF

NetCDF(Network Common Data Form)格式,簡稱nc格式,是一種自描述、與平臺無關的二進制數據文件,特別適合多維數據的存儲和交換,廣泛應用于氣象、海洋、地球科學等領域。本文介紹Windows環境下IntelFortran安裝配置NetCDF的過程。 一、系統環境及準備工作 1. 系統 Wind…

tcp/udp的socket特點

tcp &#xff1a; 綁定一個 socket 只是用來監聽&#xff0c;accept 對每個客戶端生成一個 socket 用來維護滑動窗口等。每個客戶端用一個 socket 用來維護滑動窗口等。 4 次揮手對應兩次 close 的 fin 和返回的 ack。 而三次揮手在 connect 里阻塞完成。 ?udp &#xff1a; 雙…

Linux命令top

top一、 命令二、 如何查看top輸出的結果一、 命令 top命令是Linux中的一個實時進程監控工具&#xff0c;類似于windows中的任務管理器。 基本命令 top二、 如何查看top輸出的結果 我們需要分析top輸出的結果 top輸出的結果分為上下兩部分&#xff0c;先看上半部分 第一行是…

Perl 數據庫連接

Perl 數據庫連接 概述 Perl是一種強大的編程語言&#xff0c;廣泛應用于文本處理、系統管理、網絡編程等領域。隨著數據庫技術的快速發展&#xff0c;Perl與數據庫的結合也日益緊密。本文將詳細介紹Perl數據庫連接的相關知識&#xff0c;包括常用的數據庫類型、連接方法以及一些…

jenkins從入門到精通-P1—九五小龐

1. jenkins的兩個核心為CI持續集成 CD持續部署2.jenkins在企業工作中的流程3. 學習的內容包括

第九節 Redis 事務、Redis 腳本

Redis 事務可以一次執行多個命令&#xff0c; 并且帶有以下兩個重要的保證&#xff1a; 事務是一個單獨的隔離操作&#xff1a;事務中的所有命令都會序列化、按順序地執行。事務在執行的過程中&#xff0c;不會被其他客戶端發送來的命令請求所打斷。事務是一個原子操作&#x…