C语言:冒泡排序、选择排序、快速排序、插入排序、“shell”法

环境Microsoft Windows 8,IDE:Microsoft Visual Studio 2013,语言:C语言 辅助平台CentOS

冒泡排序

冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。
它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端,故名。
****原理:****
冒泡排序算法的运作如下:(从后往前)
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
****时间复杂度****
MAX:O(N^2),MIN:O(0),average:O(N^2)
****算法稳定性****
冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以,如果两个元素相等,我想你是不会再无聊地把他们俩交换一下的;如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。
#define _CRT_SECURE_NO_WARNINGS 10
#include<stdio.h>
#include<stdlib.h>

int Bubble(int arr[],int len)
{
    int i = 0;
    int j = 0;
    int count = 0;
    for (i = 0; i < len - 1; i++)
    {
        int flag = 0;
        for (j = 0; j < len - 1 - i; j++)
        {
            count++;
            if (arr[j]>arr[j + 1])
            {
                flag = 1;
                arr[j] ^= arr[j + 1];
                arr[j + 1] ^= arr[j];
                arr[j] ^= arr[j + 1];
            }
        }
        if (!flag)
        {
            break;
        }
    }
    for (i = 0; i < len; i++)
    {
        printf("%d  ", arr[i]);
    }
    printf("\n");
    printf("is swap %d times", count);
}

int main()
{
    int arr[10] = { 11, 55, 66, 88, 44, 2, 1, 5, 6, 8 };
    int len = sizeof(arr) / sizeof(arr[0]);
    Bubble(arr, len);
    system("pause");
    return 0;
}

选择排序

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。 选择排序是不稳定的排序方法(比如序列[5, 5, 3]第一次就将第一个[5]与[3]交换,导致第一个5挪动到第二个5后面)。
****时间复杂度****
选择排序的交换操作介于 0 和 (n - 1) 次之间。选择排序的比较操作为 n (n - 1) / 2 次之间。选择排序的赋值操作介于 0 和 3 (n - 1) 次之间。
比较次数O(n^2),比较次数与关键字的初始状态无关,总的比较次数N=(n-1)+(n-2)+...+1=n*(n-1)/2。交换次数O(n),最好情况是,已经有序,交换0次;最坏情况交换n-1次,逆序交换n/2次。交换次数比冒泡排序少多了,由于交换所需CPU时间比比较所需的CPU时间多,n值较小时,选择排序比冒泡排序快。
****稳定性****
选择排序是给每个位置选择当前元素最小的,比如给第一个位置选择最小的,在剩余元素里面给第二个元素选择第二小的,依次类推,直到第n-1个元素,第n个元素不用选择了,因为只剩下它一个最大的元素了。那么,在一趟选择,如果一个元素比当前元素小,而该小的元素又出现在一个和当前元素相等的元素后面,那么交换后稳定性就被破坏了。比较拗口,举个例子,序列5 8 5 2 9,我们知道第一遍选择第1个元素5会和2交换,那么原序列中两个5的相对前后顺序就被破坏了,所以选择排序是一个不稳定的排序算法。
#define _CRT_SECURE_NO_WARNINGS 10
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#define N 10

void SelectSort(int arr[])
{
    assert(arr);
    int temp = 0;
    int i = 0;
    int j = 0;
    for (i = 0; i<N - 1; i++)
    {
        temp = i;
        for (j = i + 1; j<N; j++)
        {   
            if (arr[j] < arr[temp])
            {
                temp = j;
            }
        }
        if (temp != i)
        {
            arr[temp] ^= arr[i];
            arr[i] ^= arr[temp];
            arr[temp] ^= arr[i];
        }
    }
}

void Show(int arr[])
{
    int i = 0;
    for (i = 0; i < N; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main()
{
    int arr[N] = { 1, 5, 8, 9, 5, 2, 6, 8, 5, 8 };
    printf("before:");
    Show(arr);
    SelectSort(arr);
    printf("after: ");
    Show(arr);
    system("pause");
    return 0;
}

快速排序

// 快速排序  
int GetMidIndex(int* array, int left, int right)  
{  
    int mid = left + ((right-left)>>1);  

    if (array[left] < array[right])  
    {  
        if (array[right] < array[mid])  
            return right;  
        else if (array[left] > array[mid])  
            return left;  
        else  
            return mid;  
    }  
    else  
    {  
        if (array[right] > array[mid])  
            return right;  
        else if (array[left] < array[mid])  
            return left;  
        else  
            return mid;  
    }  
}  

// 快速排序(前后指针版本)  
int Partion1(int* array, int left, int right)  
{  
    //  
    // prev指向比key大的前一个位置  
    // cur向前寻找比key小的数据。  
    //  
    int keyIndex = GetMidIndex(array, left, right);  
    if (keyIndex != right)  
    {  
        swap(array[keyIndex], array[right]);  
    }  

    int key = array[right];  
    int prev = left - 1;  
    int cur = left;  

    while (cur < right)  
    {  
        // 找到比key的小的数据则与前面的数据进行交换  
        if(array[cur] < key && ++prev != cur)  
            swap(array[cur], array[prev]);  

        ++cur;  
    }  

    swap(array[++prev], array[right]);  

    return prev;  
}  

// 快速排序(Hoare版本)  
int Partion2(int* array, int left, int right)  
{  
    int keyIndex = GetMidIndex(array, left, right);  
    if (keyIndex != right)  
    {  
        swap(array[keyIndex], array[right]);  
    }  

    int key = array[right];  
    int begin = left;  
    int end = right;  

    while (begin < end)  
    {  
        // 从左往右找到比key大的数据时停下  
        while (array[begin] <= key && begin < end)  
            ++begin;  

        // 从右往左找到比key小的数据时停下  
        while (array[end] >= key && begin < end)  
            --end;  

        // 若位置还没有交错,则交换着两个数据。  
        if (begin < end)  
            swap(array[begin], array[end]);  
    }  

    if (begin != right)  
        swap(array[begin], array[right]);  

    return begin;  
}  

// 快速排序(挖坑法)  
int Partion3(int* array, int left, int right)  
{  
    // 三数取中  
    int keyIndex = GetMidIndex(array, left, right);  
    if (keyIndex != right)  
        swap(array[keyIndex], array[right]);  

    // key取最后一个数据  
    int key = array[right];  
    int begin = left;  
    int end = right; // end作为第一个坑  

    while (begin < end)  
    {  
        // 从左往右找到比key大的数据时停下  
        while (array[begin] <= key && begin < end)  
            ++begin;  

        // 找到一个比key大的数填到end,形成一个新的坑begin  
        if (begin < end)  
            array[end--] = array[begin];  

        // 从右往左找到比key小的数据时停下  
        while (array[end] >= key && begin < end)  
            --end;  

        // 找到一个比key小的数填到begin,形成一个新的坑end  
        if (begin < end)  
            array[begin++] = array[end];  
    }  

    // 将key填到最后留下的坑  
    array[end] = key;  

    return begin;  
}  

void QuickSort(int* array, int left, int right)  
{  
    if (left < right)  
    {  
        int boundary = Partion3(array, left, right);  

        QuickSort(array, left, boundary - 1);  
        QuickSort(array, boundary + 1, right);  
    }  
}  

// 非递归实现  
void QuickSort_NonRecursive(int* array, int left, int right)  
{  
    stack<int> s;  

    // 注意先入栈右边界,再入栈边界  
    s.push(right);  
    s.push(left);  

    while(!s.empty())  
    {  
        left = s.top();  
        s.pop();  
        right = s.top();  
        s.pop();  

        if (left < right)  
        {  
            int boundary = Partion3(array, left, right);  
            s.push(boundary - 1);  
            s.push(left);  
            s.push(right);  
            s.push(boundary + 1);  
        }  
    }  
}  

int main()
{  
    cout<<"QuickSort:"<<endl;  

    int array[SIZE] = {2, 5, 4, 9, 3, 6, 8, 7, 1, 0};  
    PrintArray(array, SIZE);  

    //  QuickSort(array, 0, SIZE - 1);  
    //  QuickSort_NonRecursive(array, 0, SIZE - 1);  
    QuickSort_OP(array, 0, SIZE - 1);  

    PrintArray(array, SIZE);   
    return 0;
}

插入排序

void InsertSort(int* array, int size)  
{  
    assert(array);  

    for (int index = 1; index < size; ++index)  
    {  
        // 将当前数据往前插入  
        int end = index - 1;  
        int tmp = array[index];  
        while (end >= 0 && tmp < array[end])  
        {  
            array[end + 1] = array[end];  
            --end;  
        }  

        // 注意这里的位置  
        array[end + 1] = tmp;  
    }  
}  

“shell”法

void ShellSort(int* array, int size)  
{  
    int gap = size;  

    while (gap > 1)  
    {  
        // Knuth提出的增量效果更好  
        gap = gap/3 + 1;  

        // 单次以gap为增量进行插入排序  
        for (int cur = gap; cur < size; ++cur)  
        {  
            int end = cur - gap;  
            int tmp = array[cur];  
            while (end >= 0 && tmp < array[end])  
            {  
                array[end + gap] = array[end];  
                end -= gap;  
            }  

            array[end + gap] = tmp;   
        }  
    }  
}  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值