C++常用排序算法

时光毁灭记忆、已成空白 提交于 2020-02-06 16:59:03

算法概述

常见的排序算可以分为以下两类:

  1. 非线性时间比较类排序:通过比较来决定元素间的相对次序,由于时间复杂度不能突破nlogn,因此称为非线性时间比较类排序
  2. 线性时间非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下限,以线性时间运行,因此称为线性时间非比较类排序
    在这里插入图片描述
    在这里插入图片描述
    排序相关概念:
  3. 稳定:如果a原本在b的前面,且a=b,排序之后a仍然在b的前面
  4. 不稳定:如果a原本在b的前面,且a=b,排序之后可能出现在b的后面

一、快速排序

快速排序(Quicksort)是对冒泡排序的一种改进。
快速排序由C. A. R. Hoare在1960年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

排序流程

  1. 首先设定一个分界值,通过该分界值将数组分成左右两个部分
  2. 将大于或等于分界值得数据集中到数组右边,小于分界值得数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值。
  3. 然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成两部分,同样在左边放置较小值,右边放置较大值,右侧的数据数据也可以做类似的处理
  4. 重复上述过程,可以看出,这是一个递归定义,通过递归将左侧部分排好序后,再递归排好右侧部分的顺序,当左右两侧部分数据排序完成后,整个数组的排序也就完成了。
C++语言

#include <iostream>
 
using namespace std;
 
void Qsort(int arr[], int low, int high){
    if (high <= low) return;
    int i = low;
    int j = high + 1;
    int key = arr[low];
    while (true)
    {
        /*从左向右找比key大的值*/
        while (arr[++i] < key)
        {
            if (i == high){
                break;
            }
        }
        /*从右向左找比key小的值*/
        while (arr[--j] > key)
        {
            if (j == low){
                break;
            }
        }
        if (i >= j) break;
        /*交换i,j对应的值*/
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
    /*中枢值与j对应值交换*/
    int temp = arr[low];
    arr[low] = arr[j];
    arr[j] = temp;
    Qsort(arr, low, j - 1);
    Qsort(arr, j + 1, high);
}
 
int main()
{
    int a[] = {57, 68, 59, 52, 72, 28, 96, 33, 24};
 
    Qsort(a, 0, sizeof(a) / sizeof(a[0]) - 1);/*这里原文第三个参数要减1否则内存越界*/
 
    for(int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
    {
        cout << a[i] << "";
    }
     
    return 0;
}
def quick_sort(data):    
    """快速排序"""    
    if len(data) >= 2:  # 递归入口及出口        
        mid = data[len(data)//2]  # 选取基准值,也可以选取第一个或最后一个元素        
        left, right = [], []  # 定义基准值左右两侧的列表        
        data.remove(mid)  # 从原始数组中移除基准值        
        for num in data:            
            if num >= mid:                
                right.append(num)            
            else:                
                left.append(num)        
        return quick_sort(left) + [mid] + quick_sort(right)    
    else:        
        return data
 
# 示例:
array = [2,3,5,7,1,4,6,15,5,2,7,9,10,15,9,17,12]
print(quick_sort(array))
# 输出为[1, 2, 2, 3, 4, 5, 5, 6, 7, 7, 9, 9, 10, 12, 15, 15, 17]

快速排序算法的思想很好理解,排序性能不错,但是代码不易实现,还需要进行递归

二、冒泡排序

它重复的走访过要排序的元素列,依次比较两个相邻元素,如果顺序错误,就将他们交换过来,走访元素的工作是重复的进行直到没有相邻元素需要交换,说明排序已完成

这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。

算法原理

  1. 比较相邻的元素,如果第一个比第二个大,就交换他们两个
  2. 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对,最后的元素应该是最大的数
  3. 针对多有元素重复以上的步骤,除了最后一个
  4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

在这里插入图片描述

def bubble_sort(nums):
    for i in range(len(nums) - 1):  # 这个循环负责设置冒泡排序进行的次数
        for j in range(len(nums) - i - 1):  # j为列表下标
            if nums[j] > nums[j + 1]:
                nums[j], nums[j + 1] = nums[j + 1], nums[j]
    return nums
 
print(bubble_sort([45, 32, 8, 33, 12, 22, 19, 97]))
# 输出:[8, 12, 19, 22, 32, 33, 45, 97]
#include <iostream>
using namespace std;
template<typename T>
//整数或浮点数皆可使用
void bubble_sort(T arr[], int len)
{
    int i, j;  T temp;
    for (i = 0; i < len - 1; i++)
        for (j = 0; j < len - 1 - i; j++)     //如果反向排序,此处j可以等于i
        if (arr[j] > arr[j + 1])
        {
            temp = arr[j];
            arr[j] = arr[j + 1];
            arr[j + 1] = temp;
        }
}
int main()
{
    int arr[] = { 61, 17, 29, 22, 34, 60, 72, 21, 50, 1, 62 };
    int len = (int) sizeof(arr) / sizeof(*arr);
    bubble_sort(arr, len);
    for (int i = 0; i < len; i++)
        cout << arr[i] << ' ';
 
    cout << endl;
 
    float arrf[] = { 17.5, 19.1, 0.6, 1.9, 10.5, 12.4, 3.8, 19.7, 1.5, 25.4, 28.6, 4.4, 23.8, 5.4 };
    len = (int) sizeof(arrf) / sizeof(*arrf);
    bubble_sort(arrf, len);
    for (int i = 0; i < len; i++)
        cout << arrf[i] << ' ';
 
    return 0;
}

冒泡排序实现较为简单,但是性能一般,最差的时间复杂度为o(n²)

三、选择排序

选择排序是一种简单直观的排序算法,它的工作原理是:第一从待排序的数据元素中选出最小的一个元素,放在序列的起始位置,然后从剩余未排序元素中寻找到最小元素,然后放到已排序的序列的末尾,直到全部待排序的数据元素的个数为零,选择排序为不稳定排序。

#include<iostream>
#include<time.h>
#include<iomanip>
using namespace std;
const int N=10;
int main()
{
    int a[N],i,j,temp,b;
    srand(time(NULL));
    for(i=0;i<N;i++)
        a[i]=rand()%100;
    for(i=0;i<N;i++)
        cout<<setw(3)<<a[i];
    cout<<endl;
    for(i=0;i<N-1;i++)
    {
        temp=i;
        for(j=i+1;j<N;j++)
        {
            if(a[temp]>a[j])
                temp=j;
        }
        if(i!=temp)
        {
            b=a[temp];
            a[temp]=a[i];
            a[i]=b;
        }
    }
    for(i=0;i<N;i++)
        cout<<setw(3)<<a[i];
    cout<<endl;
}
def selection_sort(list2):
  for i in range(0, len (list2)-1):
    min_ = i
    for j in range(i + 1, len(list2)):
      if list2[j] < list2[min_]:
        min_ = j
    list2[i], list2[min_] = list2[min_], list2[i]  # swap

注意区分冒泡排序和选择排序的区别,冒泡排序是从头开始遍历与相邻元素的大小关系,两层循环遍历就可以实现排序,选择排序是每次记住最小值的位置,注意记住的是最小值的位置,然后放置在合适的位置

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!