冒泡排序與選擇排序以及單鏈表與雙鏈表

1. 冒泡排序(Bubble Sort)

1. 原理

冒泡排序是一種 簡單的排序算法,通過 兩兩比較相鄰元素,把較大的元素逐漸 “冒泡” 到數組末尾。

  • 思路:

    1. 從數組頭開始,比較相鄰兩個元素。

    2. 如果前一個比后一個大,則交換它們。

    3. 一次完整遍歷后,最大值會移動到數組末尾。

    4. 對剩下未排序的部分重復以上步驟,直到全部排序完成。

  • 舉例:

數組:[5, 3, 8, 4]

  1. 第一次遍歷:

    • 5 vs 3 → 交換 → [3,5,8,4]

    • 5 vs 8 → 不交換 → [3,5,8,4]

    • 8 vs 4 → 交換 → [3,5,4,8]

    • 最大值 8 已經到最后

  2. 第二次遍歷:

    • 3 vs 5 → 不交換 → [3,5,4,8]

    • 5 vs 4 → 交換 → [3,4,5,8]

    • 第二大值 5 到位

  3. 第三次遍歷:

    • 3 vs 4 → 不交換 → [3,4,5,8]

    • 排序完成


2. C語言實現

#include <stdio.h>
void bubbleSort(int arr[], int n);int main(int argc,const char * argv[]) {int arr[] = {5, 3, 8, 4};int n = sizeof(arr) / sizeof(arr[0]);bubbleSort(arr, n);printf("排序結果:");for (int i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");return 0;
}void bubbleSort(int arr[], int n) 
{int i, j, temp;for (i = 0; i < n - 1; i++) // 外層控制遍歷次數{          for (j = 0; j < n - i - 1; j++) // 內層比較相鄰元素{  if (arr[j] > arr[j + 1])  // 前大于后則交換{    temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}
}

3. 特點

  1. 穩定性:穩定排序(相同元素的順序不變)

  2. 空間復雜度:O(1),原地排序

  3. 時間復雜度

    • 最好情況(已排序):O(n) 可以優化,設置標志位

    • 最壞/平均情況:O(n2)


4. 優化小技巧

  • 可以加一個 標志位 flag,如果某次遍歷沒有交換元素,則提前退出(數組已經有序):

for (i = 0; i < n - 1; i++) 
{int swapped = 0;for (j = 0; j < n - i - 1; j++) {if (arr[j] > arr[j + 1]) {temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;swapped = 1;}}if (!swapped) // 提前結束{break;} 
}

? 總結:冒泡排序思路直觀,適合小規模數據,但對大數據效率低(O(n2))。

2. 選擇排序(Selection Sort)

1. 原理

選擇排序是一種 簡單直觀的排序算法,每一次從 未排序部分選擇最小(或最大)元素 放到已排序部分的末尾(或開頭)。

  • 思路:

    1. 將整個數組分為 已排序區未排序區

    2. 每次在未排序區找到最小元素。

    3. 將最小元素與未排序區第一個元素交換。

    4. 重復以上步驟,直到數組全部排序。

  • 舉例:

數組:[5, 3, 8, 4]

  1. 第一次選擇:

    • 未排序區 [5,3,8,4] → 最小值 3

    • 交換 3 和第一個元素 5 → [3,5,8,4]

  2. 第二次選擇:

    • 未排序區 [5,8,4] → 最小值 4

    • 交換 4 和第一個未排序元素 5 → [3,4,8,5]

  3. 第三次選擇:

    • 未排序區 [8,5] → 最小值 5

    • 交換 5 和第一個未排序元素 8 → [3,4,5,8]

  4. 排序完成

2. C語言實現

#include <stdio.h>
void selectionSort(int arr[], int n);int main(int argc,const char * argv[]) {int arr[] = {5, 3, 8, 4};int n = sizeof(arr) / sizeof(arr[0]);selectionSort(arr, n);printf("排序結果:");for (int i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");return 0;
}void selectionSort(int arr[], int n) 
{int i, j, minIndex, temp;for (i = 0; i < n - 1; i++) // 外層控制已排序區{          minIndex = i; // 假設未排序區第一個是最小值                     for (j = i + 1; j < n; j++) // 遍歷未排序區{      if (arr[j] < arr[minIndex]) {minIndex = j;  // 更新最小元素索引              }}     // 交換最小值到已排序區末尾if (minIndex != i) {temp = arr[i];arr[i] = arr[minIndex];arr[minIndex] = temp;}}
}

3. 特點

  1. 穩定性:不穩定(相同元素的順序可能被交換)

  2. 空間復雜度:O(1),原地排序

  3. 時間復雜度

    • 最好/最壞/平均:O(n2)

    • 每次都必須掃描未排序區,無法提前退出

  4. 交換次數少

    • 每輪只交換一次(選最小值),相比冒泡排序可能減少交換次數


4. 冒泡排序 vs 選擇排序對比

特性冒泡排序選擇排序
思路相鄰元素兩兩比較、交換每次找到最小值放到已排序區
穩定性穩定不穩定
時間復雜度O(n2),可優化最好情況 O(n)O(n2),最好最壞情況相同
交換次數多,可能每次比較都交換少,每輪只交換一次
適合數據量小規模、部分有序小規模、無序或大數據交換少需求

? 總結:

  • 冒泡排序:直觀、穩定,但交換次數多

  • 選擇排序:交換次數少,但不穩定,比較次數不變

3.單鏈表(Singly Linked List)

1. 概念

單鏈表是一種 鏈式存儲結構,由一系列 節點(Node) 組成,每個節點包含:

  1. 數據域(data):存放節點數據

  2. 指針域(next):指向下一個節點

特點:

  • 節點在內存中 不必連續分配,通過指針鏈接

  • 第一個節點稱為 頭節點(head)

  • 最后一個節點的 next 指針為 NULL

示意圖:

head → [data|next] → [data|next] → [data|next] → NULL


2. C語言節點定義

#include <stdio.h>
#include <stdlib.h>// 定義單鏈表節點結構體
typedef struct Node 
{int data;           // 數據域struct Node* next;  // 指針域,指向下一個節點
} Node;//錯誤寫法
typedef struct Node 
{int data;           // 數據域struct Node* next;  // 指針域,指向下一個節點
} *Node; //有歧義不明白定義的是一個結構體指針還是結構體

3. 創建單鏈表(頭插法)

頭插法:新節點插入到鏈表頭部

Node* createListHead(int arr[], int n) 
{Node* head = NULL;for (int i = 0; i < n; i++) {Node* newNode = (Node*)malloc(sizeof(Node));newNode->data = arr[i];newNode->next = head; // 插入到頭部head = newNode;}return head;
}

4. 鏈表遍歷

void printList(Node* head) 
{Node* p = head;while (p != NULL) {printf("%d -> ", p->data);p = p->next;}printf("NULL\n");
}

5. 鏈表插入(指定位置)

在第 pos 個位置插入新節點(1表示頭節點之后):

void insertNode(Node** head, int pos, int value) 
{Node* newNode = (Node*)malloc(sizeof(Node));newNode->data = value;if (pos == 1) // 頭插{ newNode->next = *head;*head = newNode;return;}Node* p = *head;for (int i = 1; i < pos - 1 && p != NULL; i++) {p = p->next;}if (p == NULL)// 位置非法{ return; }newNode->next = p->next;p->next = newNode;
}

6. 鏈表刪除(指定位置)

刪除第 pos 個節點:

void deleteNode(Node** head, int pos) 
{if (*head == NULL) return;Node* temp;if (pos == 1) // 刪除頭節點{ temp = *head;*head = (*head)->next;free(temp);return;}Node* p = *head;for (int i = 1; i < pos - 1 && p->next != NULL; i++) {p = p->next;}if (p->next == NULL) // 位置非法{return; {temp = p->next;p->next = temp->next;free(temp);
}

7. 鏈表銷毀

void freeList(Node* head) 
{Node* temp;while (head != NULL) {temp = head;head = head->next;free(temp);}
}

8. 示例程序

int main(int argc,const char *argv[]) 
{int arr[] = {1, 2, 3};Node* head = createListHead(arr, 3);printf("初始鏈表: ");printList(head);insertNode(&head, 2, 9); // 在第二個位置插入9printf("插入9后: ");printList(head);deleteNode(&head, 1);    // 刪除第一個節點printf("刪除第一個節點后: ");printList(head);freeList(head);           // 釋放鏈表return 0;
}

9. 特點

  1. 動態存儲:不需要連續內存

  2. 插入/刪除方便:時間復雜度 O(1)(若已有指針)

  3. 訪問慢:查找元素需從頭開始,時間復雜度 O(n)

  4. 節省空間:不需預分配大數組

4. 雙鏈表原理

4.1 結構

每個節點包含三個部分:

說明
數據域 (data)存儲節點數據
前驅指針 (prev)指向前一個節點
后繼指針 (next)指向下一個節點

示意圖:

NULL <- [prev|data|next] <-> [prev|data|next] <-> [prev|data|next] -> NULL


4.2 特點

  1. 雙向遍歷:可以從頭到尾或從尾到頭遍歷。

  2. 插入刪除方便:直接訪問前驅節點,操作比單鏈表更高效。

  3. 內存占用多:每個節點多一個 prev 指針。

  4. 適合場景

    • 需要雙向遍歷的情況

    • 中間節點頻繁插入/刪除

    • 示例:瀏覽器歷史記錄、LRU緩存


4.3 操作實現

假設節點定義如下:

typedef struct Node {int data;           // 數據域struct Node *prev;  // 前驅指針struct Node *next;  // 后繼指針
} Node;
4.3.1 創建節點
Node* createNode(int value) {Node* newNode = (Node*)malloc(sizeof(Node));newNode->data = value;newNode->prev = NULL;newNode->next = NULL;return newNode;
}

4.3.2 遍歷

從頭到尾:

void traverseForward(Node* head) {Node* p = head;while(p) {printf("%d ", p->data);p = p->next;}printf("\n");
}

從尾到頭:

void traverseBackward(Node* tail) {Node* p = tail;while(p) {printf("%d ", p->data);p = p->prev;}printf("\n");
}

4.3.3 插入節點

在頭部插入:

void insertAtHead(Node** head, Node* newNode) {newNode->next = *head;newNode->prev = NULL;if (*head) (*head)->prev = newNode;*head = newNode;
}

在尾部插入:

void insertAtTail(Node** head, Node* newNode) {if (*head == NULL) {*head = newNode;return;}Node* tail = *head;while(tail->next) tail = tail->next;tail->next = newNode;newNode->prev = tail;
}

在指定節點后插入:

void insertAfter(Node* node, Node* newNode) {newNode->next = node->next;newNode->prev = node;if (node->next) node->next->prev = newNode;node->next = newNode;
}

4.3.4 刪除節點
void deleteNode(Node** head, Node* node) {if (!node) return;if (node->prev) node->prev->next = node->next;else *head = node->next;  // 刪除頭節點if (node->next) node->next->prev = node->prev;free(node);
}

4.3.5 查找節點
Node* search(Node* head, int value) {Node* p = head;while (p) {if (p->data == value) return p;p = p->next;}return NULL; // 未找到
}

小結

鏈表類型指針域遍歷方式插入/刪除效率內存占用
單鏈表next單向中間節點操作較慢
雙鏈表prev+next雙向中間節點操作方便

鏈表 vs 數組

特性數組鏈表
內存要求連續內存不連續,堆上分配
最大存儲量受單塊連續內存限制受總可用內存限制
插入/刪除效率O(n)O(1)(已知位置)
訪問效率O(1)O(n)

所以鏈表可以存儲比數組更多的元素,尤其是在可用連續內存不足的情況下。

具體示例請看

學生信息管理系統 —— 課程設計報告(C語言有頭雙向鏈表)-CSDN博客

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

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

相關文章

Python實現計算點云投影面積

本次我們分享一種基于 Open3D 的快速、穩健方法&#xff0c;用于從激光點云中自動提取“地面”并計算其投影面積。算法先自適應估計地面高程&#xff0c;再將地面點投影至水平面&#xff0c;隨后用凸包或最小外接矩形求取面積。整個流程無需人工干預&#xff0c;單文件即可運行…

AXI4 協議

一、AXI4簡介AXI4&#xff08;Advanced eXtensible Interface 4&#xff09;是ARM公司推出的高性能片上總線協議&#xff0c;屬于AMBA&#xff08;Advanced Microcontroller Bus Architecture&#xff09;標準的一部分。它專為高帶寬、低延遲的片上通信設計&#xff0c;廣泛應用…

《餓殍:明末千里行》Switch版試玩發布 3月13日發售

使用jQuery的常用方法與返回值分析 jQuery是一個輕量級的JavaScript庫&#xff0c;旨在簡化HTML文檔遍歷和操作、事件處理以及動畫效果的創建。本文將介紹一些常用的jQuery方法及其返回值&#xff0c;幫助開發者更好地理解和運用這一強大的庫。 1. 選擇器方法 jQuery提供了多種…

[特殊字符] 認識用戶手冊用戶手冊(也稱用戶指南、產品手冊)是通過對產品功能的清

一份優秀的用戶手冊能有效降低用戶的使用門檻&#xff0c;提升用戶體驗和工作效率。下面我將為你梳理編寫用戶手冊的核心要點、步驟和技巧。&#x1f4d6; 認識用戶手冊用戶手冊&#xff08;也稱用戶指南、產品手冊&#xff09;是??通過對產品功能的清晰解釋&#xff0c;為特…

蘋果軟件代碼混淆,iOS混淆、iOS加固、ipa安全與合規取證注意事項(實戰指南)

在移動軟件交付與合規審計中&#xff0c;蘋果軟件代碼混淆已成為保護知識產權與用戶數據的常規手段。但混淆帶來的不僅是逆向難度的提升&#xff0c;也會觸發崩潰取證、符號化&#xff08;symbolication&#xff09;、審計合規與法律證據保存等問題。本文從工程與合規雙視角出發…

Redis框架詳解

目錄 1. redis是什么 主要特點 2. redis中存儲的數據類型 2.1 String類型 2.2 List類型 2.3 Hash類型 2.4 Set類型 2.5 Zset類型 2.6 其它類型 3.redis高可用框架 1. redis是什么 Redis 是一個開源的、基于內存的數據結構存儲系統&#xff0c;是 Remote Dictionary…

每日隨機展示10個wordpress置頂文章

WordPress 置頂文章是博主根據自己的需要設置的&#xff0c;通常用于展示重要或熱門的文章。 以下是一個示例代碼&#xff0c;用于在 WordPress 主題中展示 10 個置頂文章&#xff1a; <?php // 查詢置頂文章 $sticky get_option(sticky_posts); $args array(post__in …

金融工程vs金融數學:誰更貼近量化交易?

在金融行業邁向高度數字化的今天&#xff0c;量化交易已成為頂尖金融機構的核心競爭力之一。它以數學模型為基礎&#xff0c;借助編程技術實現策略自動化&#xff0c;在高頻、中低頻、套利、因子投資等多個領域展現出強大生命力。對于有志于此的大學生而言&#xff0c;選擇一個…

實測AI Ping,一個大模型服務選型的實用工具

作為一名長期奮戰在一線的AI應用工程師&#xff0c;我在技術選型中最頭疼的問題就是&#xff1a;“這個模型服務的真實性能到底如何&#xff1f;” 官方的基準測試總是在理想環境下進行&#xff0c;而一旦投入使用&#xff0c;延遲波動、吞吐下降、高峰期服務不可用等問題就接踵…

深信服軟件:aTrustAgent異常占用問題處理

問題&#xff1a;aTrustAgent占用CPU 大早上開電腦&#xff0c;風扇轉的飛起&#xff0c;任務管理器看&#xff0c;發現是有幾個 aTrustAgent 進程搞得鬼。 印象中&#xff0c;好像沒有裝過這個軟件&#xff0c;搜了下&#xff0c;是深信服的軟件&#xff0c;不知道是不是裝哪…

基于國產銀河麒麟服務器SP3項目實戰(Nginx+Keepalive)實現高可用負載均衡

一、環境準備 192.168.113.11NginxKeepalive(Master)192.168.113.22Nginxkeepalive(Backup)192.168.113.33Nginx(web服務器)192.168.113.44 Nginx(服務器&#xff09; 二、環境搭建準備 2.1 Nginx源碼編譯安裝 參考作責之前發布《Nginx源碼編譯安裝》https://blog.csdn.net…

K近鄰:從理論到實踐

K近鄰&#xff1a;從理論到實踐 文章目錄K近鄰&#xff1a;從理論到實踐1. 核心思想2. 距離度量3. k的選擇與誤差分析3.1 近似誤差3.2 估計誤差3.3 總誤差4. kd樹的構造與搜索4.1 kd樹的構造4.2 kd樹的搜索5. 總結6. K近鄰用于iris數據集分類6.1加載數據6.2加載模型并可視化1. …

Dokcer的安裝(ubuntu-20.04.6):

Dokcer的安裝(ubuntu-20.04.6)&#xff1a; 1.添加Docker倉庫 #更新本地軟件包索引&#xff0c;獲取最新的軟件包信息 sudo apt-get update #安裝依賴包 sudo apt-get install -y \ ca-certificates \ curl \ gnupg \ lsb-release #創建密鑰存儲目錄 sudo mkdir -p /etc/apt/…

CT圖像重建原理

一、CT到底測了什么&#xff1f;硬件動作X 射線源與探測器陣列對置&#xff0c;圍著物體旋轉。每轉到一個角度 θ&#xff08;也叫一個視角 / view&#xff09;&#xff0c;源發射扇形/平行的射線束&#xff0c;探測器陣列上有很多“通道/像素/bin”&#xff08;記作索引 n&…

【pycharm】 ubuntu24.04 搭建uv環境

通過uv配置python環境 一直是conda環境 現在有個開源項目說用uv更快更好 所以在pycharm搞起。 一開始在在一個conda項目的里面某個項目里搞 發現會被conda 環境影響。 導致deepseed 安裝不了。 python 環境不對 # NOTE: We must explicitly request them as `dependencies` abo…

從軟件工程角度談企業管理

從軟件工程角度談企業管理企業管理&#xff0c;本質上是人與人之間的博弈。 管理的最大難題&#xff0c;不是定目標、不是寫流程&#xff0c;而是&#xff1a;如何讓個體的利益最大化路徑&#xff0c;與組織的整體目標一致&#xff1f; 這就是經濟學里的“激勵相容”。 在互聯網…

vue3 實現前端生成水印效果

vue3 實現前端生成水印效果首先一點哈&#xff0c;就是單純web前端生成水印只能作為警示使用&#xff0c;如果享徹底防住幾乎是不可能的&#xff0c;有無數種方式去掉web前端生成的水印&#xff0c;所以這種方式只當是一個君子協議吧。編寫水印組件 首先直接把這部分封裝成一個…

Armonia Mall超級數字生態WEB3商城的引領者

Armonia Mall是一個基于Web3技術的超級數字生態商城&#xff0c;旨在打造全球首家Web3數字普惠商城&#xff0c;幫助千萬行銷人實現數字生態創業&#xff0c;讓全球一億家庭共享數字經濟紅利。 Armonia Mall商城創始人&#xff1a;石玉華Armonia Mall七大超級機制&#xff08;模…

Axios與Java Spring構建RESTful API服務集成指南

1 前后端分離時代的技術選擇 現在的Web開發&#xff0c;前后端分離已經不是什么新鮮事了。前端用什么&#xff1f;很多團隊選擇Axios。后端呢&#xff1f;Java Spring依然是企業級應用的首選。 Axios這個JavaScript庫確實好用&#xff0c;Promise-based的設計讓異步請求變得簡單…

Django ORM多對多關系實戰指南

一、Django 多對多關系的原理 在關系型數據庫中&#xff0c;多對多關系通常需要 第三張中間表 來維護兩張表之間的對應關系。 在 Django 中&#xff0c;你只需要定義 ManyToManyField&#xff0c;Django 會自動幫你創建這張中間表。 特點&#xff1a; 可以雙向查詢&#xff08;…