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(n²)


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(n²))。

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(n²)

    • 每次都必须扫描未排序区,无法提前退出

  4. 交换次数少

    • 每轮只交换一次(选最小值),相比冒泡排序可能减少交换次数


4. 冒泡排序 vs 选择排序对比

特性冒泡排序选择排序
思路相邻元素两两比较、交换每次找到最小值放到已排序区
稳定性稳定不稳定
时间复杂度O(n²),可优化最好情况 O(n)O(n²),最好最坏情况相同
交换次数多,可能每次比较都交换少,每轮只交换一次
适合数据量小规模、部分有序小规模、无序或大数据交换少需求

✅ 总结:

  • 冒泡排序:直观、稳定,但交换次数多

  • 选择排序:交换次数少,但不稳定,比较次数不变

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;…