常用排序算法的C++实现汇总

本文汇总了多种常用排序算法的C++实现,包括插入排序、选择排序、冒泡排序、希尔排序、归并排序和快速排序等。文章提供了详细的代码示例,并通过辅助测试函数验证算法正确性和比较运行时间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

常用排序算法的C++实现汇总

以下为常用排序算法的C++实现。其中快速排序,总结实现了双路快排和三路快排。最后还实现了一个SortHelper.h的文件,可以随机生成无序或者近似有序的数据,检验数组是否已经排好序,以及各排序算法程序运行时间对比。程序源文件可以在我的github地址下载得到。

插入排序

template<typename T>
void insertionSort(vector<T>& nums)
{
	unsigned long n = nums.size();
    for(unsigned int i = 1; i < n; i ++)
    {
        // 寻找元素arr[i]合适的插入位置     
        // method 1
        #if 0
        for(unsigned int j = i; j > 0; j--)
        {
            if(nums[j] < nums[j-1] )
            {
                swap(nums[j], nums[j-1]);
            }
            else
            {
                break;
            }
        }
        #endif
        
        // method 2
        #if 0
        for(unsigned int j = i; j > 0 && nums[j] < nums[j-1]; j --)
        {
            swap(nums[j], nums[j-1]);
        }
        #endif
        
        // method 3
        #if 1
        T e = nums[i];
        unsigned int j; // j保存元素e应该插入的位置
        for(j = i; j > 0 && nums[j-1] > e; j--)
        {
            nums[j] = nums[j-1];
        }
        nums[j] = e;
        #endif
    }
    return;
}

选择排序

template<typename T>
void selectionSort(vector<T>& nums)
{
    unsigned long n = nums.size();
    for(unsigned int i = 0 ; i < n ; i ++)
    {
        int minIndex = i;
        for(unsigned int j = i + 1 ; j < n ; j ++ )
            if(nums[j] < nums[minIndex])
                minIndex = j;
        swap(nums[i] , nums[minIndex]);
    }
}

冒泡排序

Method 1

template<typename T>
void bubbleSort(vector<T>& nums)
{
    unsigned long n = nums.size();
    bool swapped;
    do
    {
        swapped = false;
        for(unsigned int i = 1; i < n; i ++)
        {
            if(nums[i-1] > nums[i])
            {
                swap(nums[i-1], nums[i]);
                swapped = true;
            }
        }
        // 优化, 每一趟Bubble Sort都将最大的元素放在了最后的位置
        // 所以下一次排序, 最后的元素可以不再考虑
        n--;
    }while(swapped);
}

Method 2

template<typename T>
void bubble2Sort(vector<T>& nums)
{
    unsigned long n = nums.size();
    int newn; // 使用newn进行优化
    do
    {
        newn = 0;
        for(unsigned int i = 1; i < n; i ++)
        {
            if(nums[i-1] > nums[i])
            {
                swap(nums[i-1], nums[i]);
                // 记录最后一次的交换位置,在此之后的元素在下一轮扫描中均不考虑
                newn = i;
            }
        }
        n = newn;
    }while(newn > 0);
}

希尔排序

template<typename T>
void shellSort(vector<T>& nums)
{

    unsigned long n = nums.size();
    // 计算 increment sequence: 1, 4, 13, 40, 121, 364, 1093...
    int h = 1;
    while(h < n/3)
    {
        h = 3 * h + 1;
    }

    while( h >= 1 )
    {
        // h-sort the array
        for(unsigned int i = h; i < n; i++)
        {
            // 对 nums[i], nums[i-h], nums[i-2*h], nums[i-3*h]... 使用插入排序
            T e = nums[i];
            int j;
            for(j = i; j >= h && e < nums[j-h]; j -= h)
            {
                nums[j] = nums[j-h];
            }
            nums[j] = e;
        }
        h /= 3;
    }
}

归并排序

// 将nums[l...mid]和nums[mid+1...r]两部分进行归并
template<typename  T>
void merge(vector<T>& nums, unsigned long l, unsigned long mid, unsigned long r)
{

    vector<T> aux(r-l+1);
    for(unsigned long i = l; i <= r; i ++)
    {
        aux[i-l] = nums[i];
    }

    // 初始化,i指向左半部分的起始索引位置l;j指向右半部分起始索引位置mid+1
    unsigned long i = l, j = mid+1;
    for(unsigned long k = l; k <= r; k ++)
    {
        if(i > mid)
        {
            // 如果左半部分元素已经全部处理完毕
            nums[k] = nums[j-l];
            j++;
        }
        else if(j > r)
        {
            // 如果右半部分元素已经全部处理完毕
            nums[k] = nums[i-l];
            i++;
        }
        else if(aux[i-l] < aux[j-l])
        {
            // 左半部分所指元素 < 右半部分所指元素
            nums[k] = nums[i-l];
            i++;
        }
        else
        {
            // 左半部分所指元素 >= 右半部分所指元素
            nums[k] = aux[j-l];
            j++;
        }
    }
}

// 递归使用归并排序,对nums[l...r]的范围进行排序
template<typename T>
void mergeSort(vector<T>& nums, unsigned long l, unsigned long r)
{

    if(l >= r)
    {
        return;
    }
    unsigned long mid = (l+r)/2;
    mergeSort(nums, l, mid);
    mergeSort(nums, mid+1, r);
    merge(nums, l, mid, r);
}

template<typename T>
void mergeSort(vector<T>& nums)
{
    unsigned long n = nums.size();
    mergeSort(nums, 0, n-1);
}

快速排序

// 双路快速排序的partition2
// 返回p, 使得nums[l...p-1] < nums[p] ; nums[p+1...r] > nums[p]
template <typename T>
unsigned long partition2(vector<T>& nums, long long l, long long r)
{
    // 随机在nums[l...r]的范围中, 选择一个数值作为标定点pivot
    srand((unsigned)time(NULL));
    long long pivot = rand() % (r-l+1) + l;
    swap(nums[l], nums[pivot]);
    T v = nums[l];

    // nums[l+1...i) <= v; nums(j...r] >= v
    long long i = l+1, j = r;
    while(true)
    {
        while(i <= r && nums[i] < v)
            i++;
        while(j >= l+1 && nums[j] > v)
            j--;
		if(i > j)
            break;
        swap(nums[i], nums[j]);
        i++;
        j--;
    }	
    swap(nums[l], nums[j]);
    return j;
}

template <typename T>
unsigned long partition(vector<T>& nums, long long l, long long r)
{

    T v = nums[l];
    long long j = l; // nums[l+1...j] < v ; nums[j+1...i) > v
    for(long long i = l + 1; i <= r; i ++)
    {
        if(nums[i] < v )
        {
            j ++;
            swap(nums[j] , nums[i]);
        }
    }
    swap(nums[l] , nums[j]);
    return j;
}

// 对nums[l...r]部分进行快速排序
template <typename T>
void quickSort(vector<T>& nums, long long l, long long r)
{
    if(l >= r)
        return;
    long long p = partition2(nums, l, r);
    if(p == 0 || l+1 == p || p + 1 == r)
        return;
    quickSort(nums, l, p-1);
    quickSort(nums, p+1, r);
}

#if 0
template <typename T>
void quickSort(vector<T>& nums)
{
    srand((unsigned)time(NULL));
    long long n = nums.size();
    quickSort(nums, 0, n-1);
}
#endif


#if 1
// 递归的三路快速排序算法
template <typename T>
void quickSort3Ways(vector<T>& nums, long long l, long long r)
{
    if(l >= r)
        return;
    // 随机在nums[l...r]的范围中, 选择一个数值作为标定点pivot
    swap(nums[l], nums[rand()%(r-l+1)+l] );
    T v = nums[l];
    
    long long lt = l;     // nums[l+1...lt] < v
    long long gt = r + 1; // nums[gt...r] > v
    long long i = l+1;    // nums[lt+1...i) == v
    while(i < gt)
    {
        if(nums[i] < v )
        {
            swap(nums[i], nums[lt+1]);
            i ++;
            lt ++;
        }
        else if(nums[i] > v )
        {
            swap(nums[i], nums[gt-1]);
            gt --;
        }
        else
        { // nums[i] == v
            i ++;
        }
    }
    swap(nums[l], nums[lt] );
    quickSort3Ways(nums, l, lt-1);
    quickSort3Ways(nums, gt, r);
}

template <typename T>
void quickSort(vector<T>& nums)
{
    srand((unsigned)time(NULL));
    long long n = nums.size();
    quickSort3Ways(nums, 0, n-1);
}
#endif

排序辅助测试函数

namespace sortHelper
{
/*
 * 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR]
 */
template<typename T>
bool generateRandomArray(vector<T>& nums, unsigned int n, T range_l, T range_r)
{
    nums.clear();
    srand((unsigned)time(NULL));
    for(unsigned int i = 0; i < n; i++)
    {
        T num =rand() % (range_r - range_l + 1) + range_l;
        nums.push_back(num);
    }
    return true;
}


/*
 * 生成一个近乎有序的数组
 * 首先生成一个含有[0...n-1]的完全有序数组, 之后随机交换swapTimes对数据
 * swapTimes定义了数组的无序程度:
 * swapTimes == 0 时, 数组完全有序
 * swapTimes 越大, 数组越趋向于无序
 */
template<typename T>
bool generateNearlyOrderedArray(vector<T>& nums, unsigned int n, int swapTimes)
{
    nums.resize(n);
    for(int i = 0 ; i < n ; i ++)
    {
        nums[i] = i;
    }
    srand((unsigned)time(NULL));
    for(unsigned int i = 0 ; i < swapTimes ; i ++)
    {
        int posx = rand()%n;
        int posy = rand()%n;
        swap(nums[posx] , nums[posy]);
    }
    return true;
}


/*
 * 打印arr数组的所有内容
 */
template<typename T>
void printArray(vector<T>& nums)
{
    unsigned int n = nums.size();
    for(unsigned int i = 0; i < n; i++)
    {
        cout<<nums[i]<<" ";
    }
    cout<<endl;
    return;
}

/*
 * 判断arr数组是否有序
 */
template<typename T>
bool isSorted(vector<T>& nums)
{
    unsigned long n = nums.size();
    for(unsigned int i = 0; i < n - 1; i++)
    {
        if(nums[i] > nums[i + 1])
        {
            return false;
        }
    }
    return true;
}

};

main函数

int main(int argc, const char * argv[])
{

    vector<int> nums;
    unsigned int n = 10000;
    int range_l = 0;
    int range_r = 1000000;
    clock_t startTime, endTime;
    
    nums.clear();
    generateRandomArray(nums, n, range_l, range_r);
    startTime = clock();
    selectionSort(nums);
    endTime = clock();
    cout<<"SelectionSort : "<< double(endTime - startTime) / CLOCKS_PER_SEC << " s"<<endl;
    isSorted(nums);

    
    nums.clear();
    generateRandomArray(nums, n, range_l, range_r);
    startTime = clock();
    insertionSort(nums);
    endTime = clock();
    cout<<"InsertionSort : "<< double(endTime - startTime) / CLOCKS_PER_SEC << " s"<<endl;
    isSorted(nums);
    
    
    nums.clear();
    generateRandomArray(nums, n, range_l, range_r);
    startTime = clock();
    bubbleSort(nums);
    endTime = clock();
    cout<<"BubbleSort : "<< double(endTime - startTime) / CLOCKS_PER_SEC << " s"<<endl;
    isSorted(nums);
  
    
    nums.clear();
    generateRandomArray(nums, n, range_l, range_r);
    startTime = clock();
    bubble2Sort(nums);
    endTime = clock();
    cout<<"Bubble2Sort : "<< double(endTime - startTime) / CLOCKS_PER_SEC << " s"<<endl;
    isSorted(nums);
    
    nums.clear();
    generateRandomArray(nums, n, range_l, range_r);
    startTime = clock();
    shellSort(nums);
    endTime = clock();
    cout<<"ShellSort : "<< double(endTime - startTime) / CLOCKS_PER_SEC << " s"<<endl;
    isSorted(nums);
    
    
    nums.clear();
    generateRandomArray(nums, n, range_l, range_r);
    startTime = clock();
    mergeSort(nums);
    endTime = clock();
    cout<<"MergeSort : "<< double(endTime - startTime) / CLOCKS_PER_SEC << " s"<<endl;
    isSorted(nums);
    
    
    return 0;
}

程序运行结果如下图所示:
程序运行结果

以上程序源文件都可以在我的github地址中下载得到。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值