首页 > 编程语言 >2025-1-15-十大经典排序算法 C++与python

2025-1-15-十大经典排序算法 C++与python

时间:2025-01-15 15:59:13浏览次数:3  
标签:sort count arr 15 python ++ C++ int 排序

文章目录

十大经典排序算法

十大经典排序算法可以分为比较排序和非比较排序:

  • 前者包括冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序;

  • 后者包括计数排序、桶排序、基数排序;

下面将详细介绍这些算法:

比较排序

1. 冒泡排序

  • 基本思想:重复地走访要排序的数列,一次比较两个数据元素,如果顺序不对则进行交换,并一直重复这样的走访操作,直到没有要交换的数据元素为止。
  • 代码示例
void bubbleSort(int arr[], int n) {
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}
def bubble_sort(arr):
    n = len(arr)
    for i in range(n):
        for j in range(0, n-i-1):
            if arr[j] > arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]
    return arr

解释

  • 该函数接受一个列表 arr 作为输入。

  • 外层循环 for i in range(n) 控制排序的轮数,每一轮将最大元素 “浮” 到末尾。

  • 内层循环 for j in range(0, n-i-1) 比较相邻元素,如果顺序错误则交换它们的位置。

  • 时间复杂度:最好情况为 O ( n ) O(n) O(n),最坏情况为 O ( n 2 ) O(n^2) O(n2)。

  • 空间复杂度: O ( 1 ) O(1) O(1)。

2. 选择排序

  • 基本思想:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
  • 代码示例
void selectionSort(int arr[], int n) {
    for (int i = 0; i < n - 1; i++) {
        int minIndex = i;
        for (int j = i + 1; j < n; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        int temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
}
def selection_sort(arr):
    for i in range(len(arr)):
        min_index = i
        for j in range(i+1, len(arr)):
            if arr[j] < arr[min_index]:
                min_index = j
        arr[i], arr[min_index] = arr[min_index], arr[i]
    return arr

解释

  • 函数 selection_sort 对列表 arr 进行排序。

  • 外层循环 for i in range(len(arr)) 确定当前要放置最小元素的位置。

  • 内层循环 for j in range(i+1, len(arr)) 寻找未排序部分的最小元素索引。

  • 时间复杂度: O ( n 2 ) O(n^2) O(n2)。

  • 空间复杂度: O ( 1 ) O(1) O(1)。

3. 插入排序

  • 基本思想:对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
  • 代码示例
void insertionSort(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;
    }
}
def insertion_sort(arr):
    for i in range(1, len(arr)):
        key = arr[i]
        j = i - 1
        while j >= 0 and key < arr[j]:
            arr[j + 1] = arr[j]
            j -= 1
        arr[j + 1] = key
    return arr

解释

  • 该函数接受列表 arr 并对其排序。

  • 从第二个元素开始,将元素 key 与其前面已排序部分的元素比较并插入正确位置。

  • 时间复杂度:最好情况为 O ( n ) O(n) O(n),最坏情况为 O ( n 2 ) O(n^2) O(n2)。

  • 空间复杂度: O ( 1 ) O(1) O(1)。

4. 希尔排序

  • 基本思想:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录 “基本有序” 时,再对全体记录进行依次直接插入排序。
  • 代码示例
void shellSort(int arr[], int n) {
    for (int gap = n / 2; gap > 0; gap /= 2) {
        for (int i = gap; i < n; i++) {
            int temp = arr[i];
            int j;
            for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) {
                arr[j] = arr[j - gap];
            }
            arr[j] = temp;
        }
    }
}
def shell_sort(arr):
    n = len(arr)
    gap = n // 2
    while gap > 0:
        for i in range(gap, n):
            temp = arr[i]
            j = i
            while j >= gap and arr[j - gap] > temp:
                arr[j] = arr[j - gap]
                j -= gap
            arr[j] = temp
        gap //= 2
    return arr
  • 函数 shell_sort 进行希尔排序。

  • 初始 gapn // 2,对相隔 gap 的元素进行插入排序,不断缩小 gap 直至为 1。

  • 时间复杂度: O ( n l o g 2 n ) O(nlog_2n) O(nlog2​n) 到 O ( n 2 ) O(n^2) O(n2) 之间。

  • 空间复杂度: O ( 1 ) O(1) O(1)。

5. 归并排序

  • 基本思想:将一个数组分成两个子数组,对每个子数组递归地进行排序,然后将排序好的子数组合并成一个有序的数组。
  • 代码示例
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, j = 0, 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++;
    }
}
void mergeSort(int arr[], int l, int r) {
    if (l < r) {
        int m = l + (r - l) / 2;
        mergeSort(arr, l, m);
        mergeSort(arr, m + 1, r);
        merge(arr, l, m, r);
    }
}
def merge_sort(arr):
    if len(arr) > 1:
        mid = len(arr) // 2
        L = arr[:mid]
        R = arr[mid:]
        merge_sort(L)
        merge_sort(R)
        i = j = k = 0
        while i < len(L) and j < len(R):
            if L[i] <= R[j]:
                arr[k] = L[i]
                i += 1
            else:
                arr[k] = R[j]
                j += 1
            k += 1
        while i < len(L):
            arr[k] = L[i]
            i += 1
            k += 1
        while j < len(R):
            arr[k] = R[j]
            j += 1
            k += 1
    return arr
  • merge_sort 函数将列表不断二分,分别对左右子列表排序,最后合并。

  • 递归调用 merge_sort 对左右子列表排序。

  • 时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)。

  • 空间复杂度: O ( n ) O(n) O(n)。

6. 快速排序

  • 基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
  • 代码示例
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++;
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    int temp = arr[i + 1];
    arr[i + 1] = arr[high];
    arr[high] = temp;
    return i + 1;
}
void quickSort(int arr[], int low, int high) {
    if (low < high) {
        int pi = partition(arr, low, high);
        quickSort(arr, low, pi - 1);
        quickSort(arr, pi + 1, high);
    }
}
def quick_sort(arr):
    if len(arr) <= 1:
        return arr
    pivot = arr[len(arr) // 2]
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    return quick_sort(left) + middle + quick_sort(right)

解释

  • 函数 quick_sort 选择一个基准元素 pivot

  • 元素被分成小于、等于、大于 pivot 的三个部分,对小于和大于部分递归排序。

  • 时间复杂度:最好情况为 O ( n l o g n ) O(nlogn) O(nlogn),最坏情况为 O ( n 2 ) O(n^2) O(n2)。

  • 空间复杂度: O ( l o g n ) O(logn) O(logn)到 O ( n ) O(n) O(n)。

7. 堆排序

  • 基本思想:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余个元素重新构造成一个堆,这样会得到个元素的次小值。如此反复执行,便能得到一个有序序列了。
  • 代码示例
void heapify(int arr[], int n, int i) {
    int largest = i;
    int l = 2 * i + 1;
    int r = 2 * i + 2;
    if (l < n && arr[l] > arr[largest])
        largest = l;
    if (r < n && arr[r] > arr[largest])
        largest = r;
    if (largest!= i) {
        int temp = arr[i];
        arr[i] = arr[largest];
        arr[largest] = temp;
        heapify(arr, n, largest);
    }
}
void heapSort(int arr[], int n) {
    for (int i = n / 2 - 1; i >= 0; i--)
        heapify(arr, n, i);
    for (int i = n - 1; i >= 0; i--) {
        int temp = arr[0];
        arr[0] = arr[i];
        arr[i] = temp;
        heapify(arr, i, 0);
    }
}
def heapify(arr, n, i):
    largest = i
    l = 2 * i + 1
    r = 2 * i + 2
    if l < n and arr[i] < arr[l]:
        largest = l
    if r < n and arr[largest] < arr[r]:
        largest = r
    if largest!= i:
        arr[i], arr[largest] = arr[largest], arr[i]
        heapify(arr, n, largest)


def heap_sort(arr):
    n = len(arr)
    for i in range(n // 2 - 1, -1, -1):
        heapify(arr, n, i)
    for i in range(n - 1, 0, -1):
        arr[i], arr[0] = arr[0], arr[i]
        heapify(arr, i, 0)
    return arr

解释

  • heapify 函数用于维护堆的性质。

  • heap_sort 先将数组构建成最大堆,然后不断交换堆顶元素与末尾元素并调整堆。

  • 时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)。

  • 空间复杂度: O ( 1 ) O(1) O(1)。

非比较排序

8. 计数排序

  • 基本思想:通过统计每个元素出现的次数,然后根据统计结果将元素依次放入有序序列中。
  • 代码示例
void countSort(int arr[], int n) {
    int max = arr[0];
    for (int i = 1; i < n; i++) {
        if (arr[i] > max) {
            max = arr[i];
        }
    }
    int count[max + 1];
    for (int i = 0; i <= max; i++) {
        count[i] = 0;
    }
    for (int i = 0; i < n; i++) {
        count[arr[i]]++;
    }
    int j = 0;
    for (int i = 0; i <= max; i++) {
        while (count[i] > 0) {
            arr[j] = i;
            j++;
            count[i]--;
        }
    }
}
def count_sort(arr):
    max_val = max(arr)
    count = [0] * (max_val + 1)
    for i in arr:
        count[i] += 1
    output = []
    for i in range(len(count)):
        for j in range(count[i]):
            output.append(i)
    return output

解释

  • count_sort 先统计元素出现次数。

  • 然后根据计数数组将元素按序添加到输出列表。

  • 时间复杂度: O ( n + k ) O(n+k) O(n+k), k k k其中是数据的范围。

  • 空间复杂度: O ( k ) O(k) O(k)。

9. 桶排序

  • 基本思想:将数据分到有限数量的桶子里,每个桶子再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。
  • 代码示例
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void bucketSort(double arr[], int n) {
    vector<double> buckets[n];
    for (int i = 0; i < n; i++) {
        int bucketIndex = n * arr[i];
        buckets[bucketIndex].push_back(arr[i]);
    }
    for (int i = 0; i < n; i++) {
        sort(buckets[i].begin(), buckets[i].end());
    }
    int index = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < buckets[i].size(); j++) {
            arr[index] = buckets[i][j];
            index++;
        }
    }
}
def bucket_sort(arr):
    if len(arr) == 0:
        return arr
    min_val, max_val = min(arr), max(arr)
    bucket_size = 5
    bucket_count = (max_val - min_val) // bucket_size + 1
    buckets = [[] for _ in range(bucket_count)]
    for i in arr:
        buckets[(i - min_val) // bucket_size].append(i)
    sorted_arr = []
    for bucket in buckets:
        insertion_sort(bucket)
        sorted_arr.extend(bucket)
    return sorted_arr

解释

  • 函数 bucket_sort 把元素分散到多个桶中。

  • 对每个桶中的元素使用插入排序并合并。

  • 时间复杂度: O ( n + k ) O(n+k) O(n+k),其中 k k k 是桶的数量。

  • 空间复杂度: O ( n + k ) O(n+k) O(n+k)。

10. 基数排序

  • 基本思想:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。
  • 代码示例
void countSortForRadix(int arr[], int n, int exp) {
    int output[n];
    int count[10] = { 0 };
    for (int i = 0; i < n; i++) {
        count[(arr[i] / exp) % 10]++;
    }
    for (int i = 1; i < 10; i++) {
        count[i] += count[i - 1];
    }
    for (int i = n - 1; i >= 0; i--) {
        output[count[(arr[i] / exp) % 10] - 1] = arr[i];
        count[(arr[i] / exp) % 10]--;
    }
    for (int i = 0; i < n; i++) {
        arr[i] = output[i];
    }
}
void radixSort(int arr[], int n) {
    int maxVal = arr[0];
    for (int i = 1; i < n; i++) {
        if (arr[i] > maxVal) {
            maxVal = arr[i];
        }
    }
    for (int exp = 1; maxVal / exp > 0; exp *= 10) {
        countSortForRadix(arr, n, exp);
    }
}
def radix_sort(arr):
    def get_digit(num, digit):
        return (num // 10**digit) % 10
    max_val = max(arr)
    exp = 0
    while 10**exp <= max_val:
        buckets = [[] for _ in range(10)]
        for i in arr:
            digit = get_digit(i, exp)
            buckets[digit].append(i)
        arr = []
        for bucket in buckets:
            arr.extend(bucket)
        exp += 1
    return arr

解释

  • radix_sort 对元素按不同位数排序。
  • 从最低位开始,将元素放入对应数字的桶中,再合并,逐位推进。

你可以使用以下方式调用这些函数:

arr = [12, 11, 13, 5, 6]
print(bubble_sort(arr.copy()))
print(selection_sort(arr.copy()))
print(insertion_sort(arr.copy()))
print(shell_sort(arr.copy()))
print(merge_sort(arr.copy()))
print(quick_sort(arr.copy()))
print(heap_sort(arr.copy()))
print(count_sort(arr.copy()))
print(bucket_sort(arr.copy()))
print(radix_sort(arr.copy()))

以上代码通过不同的排序算法实现了对列表的排序,并且通过使用 copy 避免原始列表被修改。

注意:

  • 在使用 bucket_sort 时,这里使用了 insertion_sort 对桶内元素排序,可以使用其他排序算法。

  • radix_sort 中,根据不同位数将元素放入不同桶,按顺序取出实现排序。

  • 时间复杂度: O ( d ( n + k ) O(d(n+k) O(d(n+k),其中 d d d 是数字的位数, k k k 是基数。

  • 空间复杂度: O ( n + k ) O(n+k) O(n+k)。

标签:sort,count,arr,15,python,++,C++,int,排序
From: https://blog.csdn.net/weixin_42269028/article/details/145162340

相关文章

  • python毕业设计基于python的学生管理系统的设计
    一、项目技术开发语言:Pythonpython框架:Django软件版本:python3.7/python3.8数据库:mysql5.7或更高版本数据库工具:Navicat11开发软件:PyCharm/vscode前端框架:vue.js二、项目内容和项目介绍  ......
  • c++&& SDK打包过程
     在C++中,SDK(SoftwareDevelopmentKit)打包工具的选择和使用通常取决于您的具体需求和目标平台。以下是一个详细的步骤描述,用于创建和打包一个C++SDK。这里我们假设您已经有一个C++项目需要打包为SDK。步骤一:准备你的C++项目项目结构规划:确定你的SDK包含哪些功能,比如源代......
  • Effective C++ 之【条款7:为多态基类声明virtual析构函数】
    文章目录Tips1Tips2一、为什么要有virtual析构函数?二、为什么有时候不要声明虚构函数?三、使用一下纯虚函数。TodayThinking~Tips1polymorphic(带有多态性质的)baseclasses应该声明一个virtual的虚构函数。如果class带有任何virtual函数,它就应该拥有一个virtual析构......
  • gesp(C++五级)(5)洛谷:B3929:[GESP202312 五级] 小杨的幸运数
    gesp(C++五级)(5)洛谷:B3929:[GESP202312五级]小杨的幸运数题目描述小杨认为,所有大于等于aaa的完全平方数都是他的超级幸运数。小杨还认为,所有超级幸运数的倍数都是他......
  • gesp(C++五级)(6)洛谷:B3930:[GESP202312 五级] 烹饪问题
    gesp(C++五级)(6)洛谷:B3930:[GESP202312五级]烹饪问题题目描述有NNN种食材,编号从00......
  • Python文档生成利器 - Sphinx入门指南
    目录一、安装Sphinx二、创建Sphinx项目初始化项目项目结构三、配置Sphinx基础配置扩展配置自动文档生成四、构建文档五、实战案例配置conf.py设置index.rst创建modules.rst编写Python代码构建文档六、进一步定制和优化1.使用自定义主题2.添加自定义CSS和Ja......
  • 【02】做一个精美的打飞机小游戏,python开发小游戏-鹰击长空—优雅草央千澈-持续更新-
    【02】做一个精美的打飞机小游戏,python开发小游戏-鹰击长空—优雅草央千澈-持续更新-分享源代码和游戏包供游玩-记录完整开发过程-用做好的素材来完善鹰击长空1.0.1版本背景之前优雅草央千澈在AE特效制作处博文已经完整介绍了本款游戏的素材开发,本文开始把素材利用起来放进去......
  • python毕设 校园外卖订餐系统程序+论文
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、选题背景随着互联网技术的发展,外卖订餐系统在社会各个层面广泛应用。在校园中,学生群体对外卖订餐有着较大需求。关于校园外卖订餐系统的研究,现......
  • 本地打包docker images并上传到服务器.250115
    情景:服务器dockerPull拉不下来dockerpulleaszlab/kubeasz-k8s-bin:v1.31.2Get"https://registry-1.docker.io/v2/":net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)2025-01-1417:06:35[ezdown:767]......
  • 2025毕设python医药垃圾分类管理系统程序+论文
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、选题背景关于医药垃圾分类管理的研究,现有研究多侧重于垃圾分类的一般性理论或者大型垃圾处理厂的管理模式。专门针对医药垃圾分类管理,尤其是从......