[C高手编程] C语言数据结构:排序算法与查找算法

news2024/10/10 15:17:24

在这里插入图片描述

💖💖⚡️⚡️专栏:C高手编程-面试宝典/技术手册/高手进阶⚡️⚡️💖💖
「C高手编程」专栏融合了作者十多年的C语言开发经验,汇集了从基础到进阶的关键知识点,是不可多得的知识宝典。如果你是即将毕业的学生,面临C语言的求职面试,本专栏将帮助你扎实地掌握核心概念,轻松应对笔试与面试;如果你已有两三年的工作经验,专栏中的内容将补充你在实践中可能忽略的新技术和技巧;而对于资深的C语言程序员,这里也将是一本实用的技术备查手册,提供全面的知识回顾与更新。无论处在哪个阶段,「C高手编程」都能助你一臂之力,成为C语言领域的行家里手。

概述

本章深入探讨了C语言中的两种核心算法:排序算法和查找算法。我们将从基本概念入手,逐步深入到复杂算法的实践,包括各种排序算法(如冒泡排序、选择排序、插入排序、快速排序、归并排序等)和查找算法(如顺序查找、二分查找、哈希查找等)。通过本章的学习,读者将能够理解这些算法的工作原理,并能在实际编程中正确地运用它们。

1. 排序算法

1.1 排序算法概述

  • 定义:排序算法是一种用于将一组数据按照特定顺序排列的方法。
  • 详细说明:排序算法在计算机科学中有着广泛的应用,如数据库查询、文件系统索引、搜索引擎等。排序算法的选择取决于数据集的大小、数据类型以及对稳定性的要求等因素。

1.2 冒泡排序

1.2.1 冒泡排序定义
  • 定义:冒泡排序是一种简单的排序算法,它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把它们交换过来。
  • 详细说明:冒泡排序的时间复杂度为O(n^2),在最坏的情况下性能较差,但在小数据量的情况下易于理解和实现。
1.2.2 冒泡排序实现
void bubble_sort(int arr[], int n) {
    for (int i = 0; i < n - 1; i++) {
        // 优化:设置一个标志位,如果没有发生交换,则提前退出循环
        int swapped = 0;
        for (int j = 0; j < n - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                swap(&arr[j], &arr[j + 1]);
                swapped = 1;
            }
        }
        if (swapped == 0)
            break;
    }
}

void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

1.3 选择排序

1.3.1 选择排序定义
  • 定义:选择排序是一种简单的排序算法,它首先找到数组中最小(或最大)元素放到排序序列的起始位置,然后从剩余未排序元素中继续寻找最小(或最大)元素,然后放到已排序序列的末尾。
  • 详细说明:选择排序的时间复杂度也为O(n^2),但通常比冒泡排序更快,因为它减少了不必要的交换次数。
1.3.2 选择排序实现
void selection_sort(int arr[], int n) {
    for (int i = 0; i < n - 1; i++) {
        int min_index = i;
        for (int j = i + 1; j < n; j++) {
            if (arr[j] < arr[min_index]) {
                min_index = j;
            }
        }
        swap(&arr[min_index], &arr[i]);
    }
}

1.4 插入排序

1.4.1 插入排序定义
  • 定义:插入排序是一种简单的排序算法,它通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
  • 详细说明:插入排序在小规模数据集上的性能较好,时间复杂度为O(n^2)。对于部分已排序的数据集,插入排序表现得尤其好。
1.4.2 插入排序实现
void insertion_sort(int arr[], int n) {
    for (int i = 1; i < n; i++) {
        int key = arr[i];
        int j = i - 1;
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = key;
    }
}

1.5 快速排序

1.5.1 快速排序定义
  • 定义:快速排序是一种高效的排序算法,采用分治策略来把一个序列分为较小和较大的两个子序列,然后递归地排序两个子序列。
  • 详细说明:快速排序平均情况下时间复杂度为O(n log n),但在最坏的情况下退化为O(n^2)。快速排序通常比其他O(n log n)排序算法快,因为它内部循环可以在小数组上执行得很好。
1.5.2 快速排序实现
void quick_sort(int arr[], int low, int high) {
    if (low < high) {
        int pi = partition(arr, low, high);
        quick_sort(arr, low, pi - 1);
        quick_sort(arr, pi + 1, high);
    }
}

int partition(int arr[], int low, int high) {
    int pivot = arr[high];
    int i = (low - 1);
    for (int j = low; j < high; j++) {
        if (arr[j] < pivot) {
            i++;
            swap(&arr[i], &arr[j]);
        }
    }
    swap(&arr[i + 1], &arr[high]);
    return (i + 1);
}

1.6 归并排序

1.6.1 归并排序定义
  • 定义:归并排序也是一种高效的排序算法,采用分治策略来分割数组,然后将分割后的子数组合并。
  • 详细说明:归并排序的时间复杂度为O(n log n),并且是稳定的排序算法。归并排序适用于大数据集,特别是在外部排序中。
1.6.2 归并排序实现
void merge_sort(int arr[], int l, int r) {
    if (l < r) {
        int m = l + (r - l) / 2;
        merge_sort(arr, l, m);
        merge_sort(arr, m + 1, r);
        merge(arr, l, m, r);
    }
}

void merge(int arr[], int l, int m, int r) {
    int n1 = m - l + 1;
    int n2 = r - m;
    int L[n1], R[n2];
    for (int i = 0; i < n1; i++)
        L[i] = arr[l + i];
    for (int j = 0; j < n2; j++)
        R[j] = arr[m + 1 + j];
    int i = 0;
    int j = 0;
    int k = l;
    while (i < n1 && j < n2) {
        if (L[i] <= R[j]) {
            arr[k] = L[i];
            i++;
        } else {
            arr[k] = R[j];
            j++;
        }
        k++;
    }
    while (i < n1) {
        arr[k] = L[i];
        i++;
        k++;
    }
    while (j < n2) {
        arr[k] = R[j];
        j++;
        k++;
    }
}

1.7 排序算法的高级应用

  • 定义:排序算法的高级应用包括自定义比较函数、多关键字排序等。
  • 详细说明:排序算法可以根据特定的需求进行定制,例如支持用户自定义的比较函数。
1.7.1 自定义比较函数
int compare(const void *a, const void *b) {
    return (*(int *)a - *(int *)b);
}

void custom_sort(int arr[], int n) {
    qsort(arr, n, sizeof(int), compare);
}
1.7.2 多关键字排序
struct Record {
    int id;
    int score;
};

int compare_records(const void *a, const void *b) {
    struct Record *record_a = (struct Record *)a;
    struct Record *record_b = (struct Record *)b;
    if (record_a->score == record_b->score)
        return (record_a->id - record_b->id);
    return (record_a->score - record_b->score);
}

void sort_records(struct Record records[], int n) {
    qsort(records, n, sizeof(struct Record), compare_records);
}

1.8 排序算法分析

  • 定义:排序算法分析涉及时间复杂度、空间复杂度、稳定性等方面。
  • 详细说明:不同排序算法的时间复杂度、空间复杂度和稳定性不同,因此在选择排序算法时需要考虑这些因素。
1.8.1 时间复杂度分析
  • 冒泡排序: O(n^2)
  • 选择排序: O(n^2)
  • 插入排序: O(n^2)
  • 快速排序: 平均 O(n log n),最坏 O(n^2)
  • 归并排序: O(n log n)
1.8.2 空间复杂度分析
  • 冒泡排序: O(1)
  • 选择排序: O(1)
  • 插入排序: O(1)
  • 快速排序: O(log n) (递归栈空间)
  • 归并排序: O(n) (辅助数组)
1.8.3 稳定性分析
  • 冒泡排序: 稳定
  • 选择排序: 不稳定
  • 插入排序: 稳定
  • 快速排序: 不稳定
  • 归并排序: 稳定

在这里插入图片描述

2. 查找算法

2.1 查找算法概述

  • 定义:查找算法是在给定的数据集中搜索特定元素的过程。
  • 详细说明:查找算法在数据库查询、搜索引擎等领域有着广泛的应用。不同的查找算法适用于不同类型的数据集。

2.2 顺序查找

2.2.1 顺序查找定义
  • 定义:顺序查找是一种简单的查找算法,它从数据集的第一个元素开始,按顺序比较每个元素直到找到目标元素。
  • 详细说明:顺序查找的时间复杂度为O(n)。
2.2.2 顺序查找实现
int linear_search(int arr[], int n, int x) {
    for (int i = 0; i < n; i++) {
        if (arr[i] == x)
            return i;
    }
    return -1;
}

2.3 二分查找

2.3.1 二分查找定义
  • 定义:二分查找是一种高效的查找算法,它要求数据集是有序的。算法通过将目标值与中间元素进行比较,不断缩小查找范围,直到找到目标元素。
  • 详细说明:二分查找的时间复杂度为O(log n)。
2.3.2 二分查找实现
int binary_search(int arr[], int l, int r, int x) {
    if (r >= l) {
        int mid = l + (r - l) / 2;
        if (arr[mid] == x)
            return mid;
        if (arr[mid] > x)
            return binary_search(arr, l, mid - 1, x);
        return binary_search(arr, mid + 1, r, x);
    }
    return -1;
}

2.4 哈希查找

2.4.1 哈希查找定义
  • 定义:哈希查找是一种基于哈希表的高效查找算法,它通过哈希函数将键映射到哈希表的一个位置来访问记录,这使得查找能在常数时间内完成。
  • 详细说明:哈希查找的时间复杂度在理想情况下为O(1)。
2.4.2 哈希查找实现
#define TABLE_SIZE 100
#define hash_function(key) (key % TABLE_SIZE)

struct HashTable {
    int table[TABLE_SIZE];
};

void initialize_hash_table(struct HashTable *table) {
    for (int i = 0; i < TABLE_SIZE; i++)
        table->table[i] = -1;
}

int search_hash_table(struct HashTable *table, int key) {
    int index = hash_function(key);
    if (table->table[index] == key)
        return index;
    return -1;
}

2.5 查找算法的高级应用

  • 定义:查找算法的高级应用包括多关键字查找、模糊查找等。
  • 详细说明:查找算法可以根据特定的需求进行定制,例如支持用户自定义的查找条件。
2.5.1 多关键字查找
struct Record {
    int id;
    int score;
};

struct Record records[] = {
    {1, 90},
    {2, 85},
    {3, 95},
    {4, 88},
    {5, 92}
};

int find_record_by_id(int id) {
    for (int i = 0; i < sizeof(records)/sizeof(records[0]); i++) {
        if (records[i].id == id)
            return i;
    }
    return -1;
}
2.5.2 模糊查找
#include <string.h>

int fuzzy_search(char *arr[], int n, char *pattern) {
    for (int i = 0; i < n; i++) {
        if (strstr(arr[i], pattern))
            return i;
    }
    return -1;
}

2.6 查找算法分析

  • 定义:查找算法分析涉及时间复杂度、空间复杂度、适应性等方面。
  • 详细说明:不同查找算法的时间复杂度、空间复杂度和适应性不同,因此在选择查找算法时需要考虑这些因素。
2.6.1 时间复杂度分析
  • 顺序查找: O(n)
  • 二分查找: O(log n)
  • 哈希查找: 平均 O(1),最坏 O(n) (冲突严重时)
2.6.2 空间复杂度分析
  • 顺序查找: O(1)
  • 二分查找: O(1)
  • 哈希查找: O(m) (m为哈希表大小)
2.6.3 适应性分析
  • 顺序查找: 适用于无序数据集
  • 二分查找: 适用于有序数据集
  • 哈希查找: 适用于大量数据集,需合理设计哈希函数以减少冲突

结论

本章深入探讨了C语言中的排序算法和查找算法,包括基本概念、实现方法以及高级应用。我们不仅讨论了这些算法的基本原理,还提供了详细的示例代码来帮助读者更好地理解和运用这些概念。

排序算法

  • 冒泡排序

    • 定义:通过重复遍历要排序的数列,比较相邻元素并交换。
    • 时间复杂度:O(n^2)。
    • 适用场景:适合小规模数据集。
  • 选择排序

    • 定义:通过查找最小(或最大)元素并放到已排序序列的起始位置。
    • 时间复杂度:O(n^2)。
    • 适用场景:适合小规模数据集。
  • 插入排序

    • 定义:通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
    • 时间复杂度:O(n^2)。
    • 适用场景:适合部分已排序的数据集。
  • 快速排序

    • 定义:采用分治策略将序列分为较小和较大的两个子序列。
    • 时间复杂度:平均O(n log n),最坏O(n^2)。
    • 适用场景:适用于大规模数据集。
  • 归并排序

    • 定义:采用分治策略分割数组,然后合并分割后的子数组。
    • 时间复杂度:O(n log n)。
    • 适用场景:适用于大数据集。
  • 高级应用

    • 自定义比较函数:允许用户自定义比较逻辑。
    • 多关键字排序:支持多关键字排序。

查找算法

  • 顺序查找

    • 定义:从数据集的第一个元素开始,按顺序比较每个元素直到找到目标元素。
    • 时间复杂度:O(n)。
    • 适用场景:适用于无序数据集。
  • 二分查找

    • 定义:通过将目标值与中间元素进行比较,不断缩小查找范围。
    • 时间复杂度:O(log n)。
    • 适用场景:适用于有序数据集。
  • 哈希查找

    • 定义:通过哈希函数将键映射到哈希表的一个位置来访问记录。
    • 时间复杂度:平均O(1),最坏O(n)。
    • 适用场景:适用于大量数据集。
  • 高级应用

    • 多关键字查找:支持多关键字查找。
    • 模糊查找:支持模式匹配查找。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2202352.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

开发一个exe应用工具,pdf转图片工具,pdf截成单个图片,然后全量修整没用的白边

pdf转图片工具 图片裁剪白边工具 window系统exe应用工具下载地址https://download.csdn.net/download/websmallrabbit/89864476如果有帮助到您还请动动手帮忙点赞&#xff0c;关注&#xff0c;评论转发&#xff0c;感谢啦&#xff01;&#x1f495;&#x1f495;&#x1f495;&…

记一次详细的实战渗透

声明&#xff1a;本文仅限于技术讨论与分享&#xff0c;严禁用于非法途径。若读者因此作出任何危害网络安全行为后果自负&#xff0c;与本号及原作者无关。 前言 一次授权的渗透测试&#xff0c;过程比较详细&#xff0c;充满了巧合&#xff0c;也算比较有意思直接记录一下&a…

SpringBoot访问web中的静态资源

SpringBoot访问web中的静态资源&#xff0c;有两个方式&#xff1a; 1、SpringBoot默认指定了一些固定的目录结构&#xff0c;静态资源放到这些目录中的某一个&#xff0c;系统运行后浏览器就可以访问到 ① 关键是SpringBoot默认指定的可以存放静态资源的目录有哪些&#xff…

这几个被淘汰的Python库,请不要再用!

随着每个 Python 版本的发布&#xff0c;都会添加新模块&#xff0c;并引入新的更好的做事方式&#xff0c;虽然我们都习惯了使用好的旧 Python 库和某些做事方式&#xff0c;但现在也时候升级并利用新的和改进的模块及其特性了。 这里插播一条粉丝福利&#xff0c;如果你正在…

图片美化SDK解决方案,赋能H5与小程序极致体验

无论是社交媒体分享、电商产品展示&#xff0c;还是个人日常生活的记录&#xff0c;一张经过精心美化的图片总能瞬间吸引眼球&#xff0c;传递出更加丰富和动人的信息。如何在不增加应用体积、不牺牲用户体验的前提下&#xff0c;为H5页面和小程序提供媲美原生APP的图片美化功能…

二、IOC容器

文章目录 1. IOC的底层原理1.1 什么是IOC1.2 IOC 底层原理1.3 画图讲解 IOC 底层原理 2. IOC接口&#xff08;BeanFactory&#xff09;3. IOC 操作 Bean 管理&#xff08;概念&#xff09;3.1 什么是Bean管理3.2 Bean管理操作的两种方式 4. IOC操作 Bean 管理&#xff08;基于 …

go发送邮件:在Go语言中实现发邮件的教程?

go发送邮件的教程指南&#xff1f;怎么使用Go语言发送电子邮件&#xff1f; Go语言&#xff0c;作为一种简洁、高效且并发性强的编程语言&#xff0c;自然也提供了丰富的库来支持邮件发送功能。AokSend将详细介绍如何在Go语言中实现发送邮件的功能&#xff0c;帮助你快速掌握这…

Video Ocean,又一AI视频生成神器!

Video Ocean&#xff0c;又一AI视频生成神器&#xff01; 引言 大家好&#xff0c;今天想和大家聊聊一个特别的工具——Video Ocean。在如今这个短视频盛行的时代&#xff0c;大家都知道&#xff0c;制作一个吸引眼球的视频可不是一件简单的事情。传统的视频编辑软件复杂又费…

Gin解说

Gin是一个用Go语言编写的高性能、开源的Web框架&#xff0c;它被设计为简单、快速和灵活。Gin非常适合用于构建RESTful API和微服务。以下是Gin框架的一些核心特点&#xff1a; 特点 1.高性能&#xff1a;Gin使用了高速的HTTP路由器&#xff0c;它基于Radix树实现&#xff0c…

AI直播元年:盘点2025年经典实用的十款AI直播工具,特别是第一款!

AI直播元年&#xff1a;盘点2025年经典实用的十款AI直播工具&#xff0c;特别是第一款&#xff01; 随着人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;直播行业正经历着前所未有的变革。2025年&#xff0c;被誉为“AI直播元年”&#xff0c;这一年见证了众多…

2.4 Service服务层

今天&#xff0c;我将向大家介绍在Spring Boot应用程序中实现Service层的方法&#xff0c;并通过实战演示如何测试Service层。 首先&#xff0c;让我们回顾一下Service层在MVC架构中的作用。Service层位于Model和Controller之间&#xff0c;主要负责处理业务逻辑。它封装了应用…

多线程—— Thread 类及常见用法(详解)

前言 本篇文章会介绍 Java 中的 Thread 类常见的构造方法、常见属性及其常见的用法&#xff0c;会列举一些代码例子来更直观的感受每个方法是作用&#xff0c;文章还会介绍 Java 中线程的状态及他们之间的转换关系&#xff0c;那么下面就开始今天的分享吧~~ 一、常见构造方法 …

ant-design-vue 可输入表格的校验方法

1、思路&#xff0c;首先用a-form包裹a-table&#xff0c;( 主要是name的取值问题&#xff0c;要严格按照[数据源,index,校验的字段]来) <a-form ref"form" :model"formData" :rules"rules"><a-table :dataSource"formData.table…

charAt,chartCodeAt,codePointAt,fromCodePoint,fromCharCode

生僻字的length算2,有些空格是特殊空格,比如\u3000 u3000不是全角空格&#xff0c;u3000是表意字空格&#xff08;Ideographic Space&#xff09;&#xff0c;宽度和一个表意字&#xff08;汉字&#xff09;相同。它应当被当做汉字来处理。比如&#xff0c;在一些排版中&#x…

Vxe UI vue vxe-table select 下拉框选项列表数据量超大过大时卡顿解决方法

Vxe UI vue vxe-table vxe-grid select 下拉框选项列表数据量超大过大时卡顿解决方法 查看 github vxe-table 官网 vxe-table 本身支持虚拟滚动&#xff0c;数据量大也是支持的&#xff0c;但是如果在可编辑表格中使用下拉框&#xff0c;下拉框的数据量超大时&#xff0c;可能…

【源码+文档+调试讲解】宜家宜业物业管理系统node.js框架

摘 要 近年来&#xff0c;科技飞速发展&#xff0c;在经济全球化的背景之下&#xff0c;互联网技术将进一步提高社会综合发展的效率和速度&#xff0c;互联网技术也会涉及到各个领域&#xff0c;而宜家宜业物业管理系统在网络背景下有着无法忽视的作用。信息管理系统的开发是…

Chromium 如何构建一个单独exe c++

1、在src目录下新建一个jdtest文件夹 src\jdtest 2、在jdtest文件下添加BUILD.gn jdtest.cc build.gn 内容如下&#xff1a; # Copyright 2014 The Chromium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file…

python27_strip()去除函数

strip()去除函数 # 示例字符串 s1 "*hello*world*oh*yeah*" s2 " helloworldohyeah "# 使用 strip() 去除两端的 * def StrStrip(a):result_strip a.strip("*")return result_strip# 替换成空字符串 def StrReplaceNull(a):result_empty a.…

OOOPS:零样本实现360度开放全景分割,已开源 | ECCV‘24

全景图像捕捉360的视场&#xff08;FoV&#xff09;&#xff0c;包含了对场景理解至关重要的全向空间信息。然而&#xff0c;获取足够的训练用密集标注全景图不仅成本高昂&#xff0c;而且在封闭词汇设置下训练模型时也受到应用限制。为了解决这个问题&#xff0c;论文定义了一…

软考《信息系统运行管理员》- 4.2信息系统软件运维的管理

4.2信息系统软件运维的管理 管理流程 信息系统软件运维服务的四个关键要素是&#xff1a;人员、资源、技术和过程&#xff0c;每个要素通过关键 指标反映运维服务的能力。 人员 确保提供信息系统软件运维服务的相关人员具备应有的运维服务能力&#xff0c;主要从人员管理、 …