十大排序算法(C++)

面试常考的排序算法(C++)

常考知识点:

1)什么是稳定排序算法?

稳定排序算法是指能够保持相等元素原来顺序的排序算法。在排序过程中,如果两个具有相等“键”(排序依据的值)的元素在排序后仍然保持它们在原序列中的相对顺序不变,那么这种排序算法就是稳定的。

2)哪些排序是稳定的,哪些是不稳定的?

稳定的:冒泡排序、插入排序、归并排序、计数排序、桶排序、基数排序

不稳定的:选择排序、快速排序、希尔排序、堆排序

1、冒泡排序

原理:

比较相邻的元素。如果第一个比第二个大,就交换他们两个。

对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。

针对所有的元素重复以上的步骤,除了最后一个。

持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较

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

空间复杂度:O(1)

代码:

#include <vector> // 包含vector库,用于存储和操作动态数组

// 函数定义:冒泡排序
void bubbleSort(std::vector<int>& nums) {
    int n = nums.size(); // 获取数组的长度
    bool swapped; // 声明一个布尔变量,用于标记在一次遍历中是否发生了交换
    // 外层循环:遍历数组的每个元素
    for (int i = 0; i < n - 1; i++) {
        swapped = false; // 在每次遍历开始时,设置交换标志为false
        // 内层循环:从第一个元素到"未排序的最后一个元素"
        for (int j = 0; j < n - i - 1; j++) {
            // 比较相邻元素,如果左边的大于右边的,则交换它们
            if (nums[j] > nums[j + 1]) {
                std::swap(nums[j], nums[j + 1]); // 使用std::swap进行元素交换
                swapped = true; // 发生了交换,将交换标志设置为true
            }
        }
        // 如果在一次遍历中没有发生交换,说明数组已经有序,跳出循环
        if (!swapped) break;
    }
}

int main() {
    std::vector<int> nums = {64, 34, 25, 12, 22, 11, 90}; // 初始化一个需要排序的数组
    bubbleSort(nums); // 调用冒泡排序函数
    
    // 打印排序后的数组
    for (int i = 0; i < nums.size(); i++) {
        std::cout << nums[i] << " ";
    }
    std::cout << std::endl;
    return 0;
}

2、快速排序

原理:

1.从数列中挑出一个元素,称为 “基准”(pivot);

2.重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;

3.递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

时间复杂度:O(nlogn)

空间复杂度:O(logn)

代码:

// 快速排序函数定义,从数组arr中的索引left到right进行排序
void quickSort(int left, int right, vector<int>& arr)
{
    // 如果当前分段只有一个元素或无元素,直接返回
	if(left >= right)
		return;
	int i, j, base, temp;
	i = left, j = right; // 初始化i为左边界,j为右边界
	base = arr[left];  // 选择最左边的元素作为基准数

	while (i < j) // 当i和j未相遇时,循环继续
	{
	    // 从右向左查找第一个小于基准数的元素
		while (arr[j] >= base && i < j)
			j--;
		// 从左向右查找第一个大于基准数的元素
		while (arr[i] <= base && i < j)
			i++;
		// 如果找到且i<j,则交换两个元素的位置
		if(i < j)
		{
			temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
		}
	}
	// 将基准数归位到中间,此时基准数左侧的都比它小,右侧的都比它大
	arr[left] = arr[i];
	arr[i] = base;

	// 对基准数左侧的子数组递归排序
	quickSort(left, i - 1, arr);
	// 对基准数右侧的子数组递归排序
	quickSort(i + 1, right, arr);
}


//另一种写法
// 快速排序
void QuickSort(int arr[], int start, int end)
{
	if (start >= end) // 如果数组只有一个元素或没有元素,直接返回
		return;
	int i = start; // 左指针
	int j = end; // 右指针
	int baseval = arr[start]; // 基准数,这里选取子数组的第一个数
	
	while (i < j) // 当左右指针没有相遇时循环
	{
		// 从右向左找到第一个比基准数小的数
		while (i < j && arr[j] >= baseval)
		{
			j--; // 右指针左移
		}
		if (i < j) // 找到后将其赋值给左指针所指位置,然后左指针右移
		{
			arr[i] = arr[j];
			i++;
		}
		// 从左向右找到第一个比基准数大的数
		while (i < j && arr[i] < baseval)
		{
			i++; // 左指针右移
		}
		if (i < j) // 找到后将其赋值给右指针所指位置,然后右指针左移
		{
			arr[j] = arr[i];
			j--;
		}
	}
	// 将基准数放到中间位置(左右指针相遇的位置)
	arr[i] = baseval;
	// 对左半部分递归排序
	QuickSort(arr, start, i - 1);
	// 对右半部分递归排序
	QuickSort(arr, i + 1, end);
}

3、堆排序

原理:堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法:每个结点的值都大于等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于等于其左右孩子结点的值,称为小顶堆。该算法时间复杂度为O(n log n)。

1.将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;

2.将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];

3.由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

时间复杂度:O(nlogn)

空间复杂度:O(1)

代码:

#include <iostream>
#include <vector>
using namespace std;

void heapify(vector<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) {
        swap(arr[i], arr[largest]);
        heapify(arr, n, largest);
    }
}

// 堆排序函数
void heapSort(vector<int>& arr) {
    int n = arr.size();

    // 从最后一个非叶子节点开始,对数组进行堆化
    for (int i = n / 2 - 1; i >= 0; i--)
        heapify(arr, n, i);

    // 一个个从堆顶取出元素,然后重建堆
    for (int i = n - 1; i > 0; i--) {
        // 将当前根节点,即最大元素移到数组末尾
        swap(arr[0], arr[i]);

        // 对减小的堆进行堆化
        heapify(arr, i, 0);
    }
}

int main() {
    vector<int> arr = {12, 11, 13, 5, 6, 7,22,33};
    heapSort(arr);

    cout << "Sorted array is \n";
    for(int i = 0; i < arr.size(); i++)
        cout << arr[i] << " ";
    return 0;
}
/*
heapify函数负责维护堆的性质。给定一个数组和一个节点索引i,这个函数确保以索引i为根的子树是一个最大堆,前提是该子树的所有子树已经是最大堆。
heapSort函数实现了堆排序算法。它首先通过从最后一个非叶子节点开始向上构建最大堆,然后通过交换堆顶元素(数组的第一个元素)与最后一个元素,并重新对堆顶元素执行heapify操作来排序数组。
*/

4、归并排序

原理:

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。代价是需要额外的内存空间。若将两个有序表合并成一个有序表,称为2-路归并。 该算法时间复杂度为O(n log n)。

1.把长度为n的输入序列分成两个长度为n/2的子序列;

2.对这两个子序列分别采用归并排序;

3.将两个排序好的子序列合并成一个最终的排序序列。

时间复杂度:O(nlogn)

空间复杂度:O(n)

代码:

#include <iostream>
#include <vector>

using namespace std;

// 合并两个已排序的子数组
// arr: 原始数组
// l: 左子数组的起始索引
// m: 左子数组和右子数组的分界索引
// r: 右子数组的结束索引
void merge(vector<int>& arr, int l, int m, int r) {
    int n1 = m - l + 1; // 左子数组的长度
    int n2 = r - m; // 右子数组的长度

    // 创建临时数组存储左右子数组
    vector<int> L(n1), R(n2);

    // 复制数据到临时数组L[]和R[]
    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];

    // 合并临时数组回原数组arr
    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++;
    }

    // 复制L[]的剩余元素到arr[],如果有
    while (i < n1) {
        arr[k] = L[i];
        i++;
        k++;
    }

    // 复制R[]的剩余元素到arr[],如果有
    while (j < n2) {
        arr[k] = R[j];
        j++;
        k++;
    }
}

// 归并排序函数
// arr: 待排序的数组
// l: 排序子数组的起始索引
// r: 排序子数组的结束索引
void mergeSort(vector<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);
    }
}

// 主函数展示归并排序的使用
int main() {
    vector<int> arr = {12, 11, 13, 5, 6, 7};
    cout << "Given array is \n";
    for(int i : arr) {
        cout << i << " ";
    }
    cout << endl;

    mergeSort(arr, 0, arr.size() - 1);

    cout << "\nSorted array is \n";
    for(int i : arr) {
        cout << i << " ";
    }
    cout << endl;
    return 0;
}

5、插入排序

原理:插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。例如要将数组arr=[4,2,8,0,5,1]排序,可以将4看做是一个有序序列,将[2,8,0,5,1]看做一个无序序列。无序序列中2比4小,于是将2插入到4的左边,此时有序序列变成了[2,4],无序序列变成了[8,0,5,1]。无序序列中8比4大,于是将8插入到4的右边,有序序列变成了[2,4,8],无序序列变成了[0,5,1]。以此类推,最终数组按照从小到大排序。该算法的时间复杂度为O(n^2)。

1.从第一个元素开始,该元素可以认为已经被排序;

2.取出下一个元素,在已经排序的元素序列中从后向前扫描;

3.如果该元素(已排序)大于新元素,将该元素移到下一位置;

4.重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;

5.将新元素插入到该位置后;

6.重复步骤2~5。

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

空间复杂度:O(1)

代码:

#include <iostream>
#include <vector>

using namespace std;

// 插入排序函数
void insertionSort(vector<int>& arr) {
    int n = arr.size(); // 获取数组的大小
    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 = j - 1; // 移动到下一个要比较的元素
        }
        arr[j + 1] = key; // 在正确的位置插入当前元素
    }
}

// 主函数
int main() {
    vector<int> arr = {12, 11, 13, 5, 6, 7}; // 初始化一个数组
    cout << "Given array is \n"; 
    for(int i : arr) {
        cout << i << " "; // 打印原始数组
    }
    cout << endl;

    insertionSort(arr); // 调用插入排序函数

    cout << "Sorted array is \n";
    for(int i : arr) {
        cout << i << " "; // 打印排序后的数组
    }
    cout << endl;

    return 0;
}

6、选择排序

原理: 选择排序是一种简单直观的排序算法,无论什么数据进去都是 O(n²) 的时间复杂度。所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。具体来说,假设长度为n的数组arr,要按照从小到大排序,那么先从n个数字中找到最小值min1,如果最小值min1的位置不在数组的最左端(也就是min1不等于arr[0]),则将最小值min1和arr[0]交换,接着在剩下的n-1个数字中找到最小值min2,如果最小值min2不等于arr[1],则交换这两个数字,依次类推,直到数组arr有序排列。算法的时间复杂度为O(n^2)。

1.首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。

2.再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。

3.重复第二步,直到所有元素均排序完毕。

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

空间复杂度:O(1)

代码:

#include <iostream>
#include <vector>

using namespace std;

// 选择排序函数
void selectionSort(vector<int>& arr) {
    int n = arr.size(); // 获取数组的大小
    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]); // 交换最小元素与第i个元素
    }
}

// 主函数
int main() {
    vector<int> arr = {64, 25, 12, 22, 11}; // 初始化一个数组
    cout << "Given array is \n";
    for(int i : arr) {
        cout << i << " "; // 打印原始数组
    }
    cout << endl;

    selectionSort(arr); // 调用选择排序函数

    cout << "Sorted array is \n";
    for(int i : arr) {
        cout << i << " "; // 打印排序后的数组
    }
    cout << endl;

    return 0;
}

7、希尔排序

原理: 希尔排序(Shell’s Sort)在插入排序算法的基础上进行了改进,算法的时间复杂度与前面几种算法相比有较大的改进,但希尔排序是非稳定排序算法。其算法的基本思想是:先将待排记录序列分割成为若干子序列分别进行插入排序,待整个序列中的记录"基本有序"时,再对全体记录进行一次直接插入排序。该算法时间复杂度为O(n log n)。

1.选择一个增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1;

2.按增量序列个数 k,对序列进行 k 趟排序;

3.每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

空间复杂度:O(1)

代码:

#include <iostream>
#include <vector>

using namespace std;

// 希尔排序函数
void shellSort(vector<int>& arr) {
    int n = arr.size(); // 获取数组的大小
    // 初始增量gap为数组长度的一半,每次循环后减半
    for (int gap = n/2; gap > 0; gap /= 2) {
        // 从第gap个元素开始,逐个对其所在组进行直接插入排序
        for (int i = gap; i < n; i += 1) {
            // 添加arr[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;
        }
    }
}

// 主函数
int main() {
    vector<int> arr = {46, 74, 53, 14, 26, 36, 86, 65, 27, 34};
    cout << "Given array is \n";
    for(int i : arr) {
        cout << i << " "; // 打印原始数组
    }
    cout << endl;

    shellSort(arr); // 调用希尔排序函数

    cout << "Sorted array is \n";
    for(int i : arr) {
        cout << i << " "; // 打印排序后的数组
    }
    cout << endl;

    return 0;
}

8、计数排序

原理: 计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。计数排序不是基于比较的排序算法。而是 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。当输入的元素是 n 个 0 到 k 之间的整数时,它的运行时间是 Θ(n + k)。计数排序不是比较排序,排序的速度快于任何比较排序算法。由于用来计数的数组C的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),这使得计数排序对于数据范围很大的数组,需要大量时间和内存。该算法时间复杂度为O(n+k)。

1.找出待排序的数组中最大和最小的元素;

2.统计数组中每个值为i的元素出现的次数,存入数组C的第i项;

3.对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加);

4.反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1。

时间复杂度:O(n+k)

空间复杂度:O(k)

代码:

#include <iostream>
#include <vector>
#include <algorithm> // 用于 std::max_element

using namespace std;

// 计数排序函数
void countingSort(vector<int>& arr) {
    if (arr.empty()) return; // 如果数组为空,则直接返回

    // 找到数组中的最大值
    int maxVal = *max_element(arr.begin(), arr.end());

    // 创建计数数组,并初始化为0
    vector<int> count(maxVal + 1, 0);

    // 计算每个元素的出现次数
    for (int num : arr) {
        count[num]++;
    }

    // 根据计数数组,对原数组进行排序
    int index = 0; // 用于原数组的索引
    for (int i = 0; i <= maxVal; i++) {
        while (count[i] > 0) { // 如果当前值出现过
            arr[index++] = i; // 将其填回原数组
            count[i]--; // 减少计数
        }
    }
}

// 主函数
int main() {
    vector<int> arr = {4, 2, 2, 8, 3, 3, 1};
    cout << "Given array is \n";
    for (int num : arr) {
        cout << num << " "; // 打印原始数组
    }
    cout << endl;

    countingSort(arr); // 调用计数排序函数

    cout << "Sorted array is \n";
    for (int num : arr) {
        cout << num << " "; // 打印排序后的数组
    }
    cout << endl;

    return 0;
}

9、桶排序

原理: 桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。为了使桶排序更加高效,我们需要做到这两点:在额外空间充足的情况下,尽量增大桶的数量;使用的映射函数能够将输入的 N 个数据均匀的分配到 K 个桶中。该算法时间复杂度为O(n+k)。

桶排序算法的原理如下:

1.设置一个定量的数组当作空桶;

2.遍历输入数据,并且把数据一个一个放到对应的桶里去;

3.对每个不是空的桶进行排序;

4.从不是空的桶里把排好序的数据拼接起来。

时间复杂度:O(n+k)

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

代码:

#include <iostream>
#include <vector>
#include <algorithm> // 用于 std::sort

using namespace std;

// 桶排序函数
void bucketSort(float arr[], int n) {
    // 1. 创建n个空桶
    vector<float> buckets[n];
    
    // 2. 把数组arr中的元素均匀分配到桶中
    // 假设输入数据是均匀分布的,则可以直接使用元素值乘以n来确定元素应该分配到哪个桶
    for (int i = 0; i < n; i++) {
        int bucketIdx = n * arr[i]; // 计算当前元素应该放入哪个桶
        buckets[bucketIdx].push_back(arr[i]);
    }
    
    // 3. 分别对每个桶进行排序,这里使用了STL的sort函数
    for (int i = 0; i < n; i++) {
        sort(buckets[i].begin(), buckets[i].end());
    }
    
    // 4. 合并桶:将所有桶中的元素合并回原数组
    int index = 0;
    for (int i = 0; i < n; i++) {
        for (size_t j = 0; j < buckets[i].size(); j++) {
            arr[index++] = buckets[i][j];
        }
    }
}

// 主函数
int main() {
    float arr[] = {0.42, 0.32, 0.23, 0.52, 0.25, 0.47, 0.51};
    int n = sizeof(arr)/sizeof(arr[0]);

    cout << "Given array is \n";
    for(int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;

    bucketSort(arr, n); // 调用桶排序函数

    cout << "Sorted array is \n";
    for(int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;

    return 0;
}

10、基数排序

原理:基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。该算法时间复杂度为O(n+k)。

基数排序算法的原理如下:

1.取得数组中的最大数,并取得位数;

2.arr为原始数组,从最低位开始取每个位组成radix数组;

3.对radix进行计数排序(利用计数排序适用于小范围数的特点)。

时间复杂度:O(n*k)

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

代码:

#include <iostream>
#include <vector>
#include <algorithm> // 使用std::max_element

using namespace std;

// 获取数组中的最大值
int getMax(const vector<int>& arr) {
    return *max_element(arr.begin(), arr.end());
}

// 计数排序,作为基数排序的一个步骤,按照指定的位数排序
void countSort(vector<int>& arr, int exp) {
    vector<int> output(arr.size()); // 存储"被排序数据"的临时数组
    vector<int> count(10, 0); // 计数数组,考虑到每位数字都是0-9

    // 计算每个数字出现的次数
    for (int i = 0; i < arr.size(); i++)
        count[(arr[i] / exp) % 10]++;

    // 更改count[i],现在包含实际在输出数组中的位置信息
    for (int i = 1; i < 10; i++)
        count[i] += count[i - 1];

    // 构建输出数组
    for (int i = arr.size() - 1; i >= 0; i--) {
        output[count[(arr[i] / exp) % 10] - 1] = arr[i];
        count[(arr[i] / exp) % 10]--;
    }

    // 将输出数组复制回arr,以便下一个位也能按照这种顺序排序
    for (int i = 0; i < arr.size(); i++)
        arr[i] = output[i];
}

// 基数排序函数
void radixSort(vector<int>& arr) {
    // 找到最大数,以确定排序所需的最大位数
    int m = getMax(arr);

    // 从最低位开始对每个位进行计数排序
    for (int exp = 1; m / exp > 0; exp *= 10)
        countSort(arr, exp);
}

// 主函数
int main() {
    vector<int> arr = {170, 45, 75, 90, 802, 24, 2, 66};
    cout << "Given array is \n";
    for (int i : arr)
        cout << i << " ";
    cout << endl;

    radixSort(arr);

    cout << "Sorted array is \n";
    for (int i : arr)
        cout << i << " ";
    cout << endl;

    return 0;
}

问题

1、每个排序算法适用的场景?

各种排序算法都有其适用的场景和应用,下面是一些常见排序算法及其适用情况:

  1. 冒泡排序:当数据量较小或者大部分元素已经有序时,适合使用。应用在一些对时间要求不严格的简单排序场景。

  2. 选择排序:和冒泡排序类似,数据量小时适合使用。算法简单稳定。

  3. 插入排序:较适用于少量数据排序,数据基本有序时效率高,简单。对于少量元素的排序非常有效。

  4. 希尔排序:较适合于大规模文件排序,比较好的选择。在大规模无序数据排序时较高效。

  5. 归并排序:较适合于数据量较大的排序应用,排序性能高效稳定,多种场景都适用。但空间复杂度较高。

  6. 快速排序:在大多数实际应用场景中,效率都很高,是最常用的排序算法之一。对于大数据量和随机数据有较好效果。

  7. 堆排序:当内存有限时比较适合,因为只需要一个数据存储空间就能完成排序。也适合一些连续视频流排序。

  8. 计数排序:适合数值很小的整数排序,对于数据范围较小有较高的效率。常用于基数排序算法中的一个子过程。

  9. 桶排序:适合于外部排序,即可后台调入操作,很适合大数据量的分布式系统排序。

  10. 基数排序:适合数值很大的整数排序。常用于分布式系统中的排序,也适用于负载均衡的排序。

总的来说,冒泡、选择、插入等简单排序适合数据规模较小的排序;快速排序和归并排序很适合大数据量排序;堆排序、计数排序等特定算法针对特定场景很高效。在实际应用中要根据具体数据特征和排序场景选择合适的算法。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
十大经典排序算法中的三种排序算法分别是冒泡排序、希尔排序和选择排序。 冒泡排序是一种简单直观的入门排序算法,其原理是从第一个元素开始,与后面的元素逐个比较,如果顺序不对就交换,直到没有可比较的元素为止。 希尔排序是插入排序的一种高效改进版本,也称为“缩小增量排序”。该算法将记录按下标的一定增量分组,对每组使用直接插入排序算法排序,随着增量的逐渐减小,每组包含的关键词越来越多,当增量减至1时,整个文件被分成一组,排序完成。 选择排序是基于冒泡排序的优化,减少了交换的次数。每次遍历后找出最小/最大的元素,然后与第一个元素交换,再从剩下的元素中重复这个过程。 以上是关于冒泡排序、希尔排序和选择排序的简要介绍。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [c++十大经典排序算法](https://blog.csdn.net/zhoujiajie0521/article/details/122183332)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [十大经典排序算法C++)](https://blog.csdn.net/qq_52639492/article/details/122106147)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星空有大海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值