扩大
缩小

常见的六种排序算法实现

常见的六种排序算法实现

在写六种排序先写两个辅助的函数

交换数组的元素函数swap

/*辅助交换函数*/
int Swap(int* str, int pos1, int pos2)
{
    if (str == NULL)
    {
        return -1;
    }
    if (pos1 < 0 || pos2 < 0)
    {
        return -2;
    }
    /*交换数组pos1的值和pos2的值*/
    int temp = str[pos1];
    str[pos1] = str[pos2];
    str[pos2] = temp;
    return 0;
}
/*打印数组元素*/
void PrintArraryElement(int* str, int length)
{
    
    assert(str != NULL);
    printf("\t\t\t");
    for (int i = 0; i < length; i++)
    {
        printf("%d\t", str[i]);
    }
    printf("\n");

}

选择排序

/*选择排序*/
int SelectSort(int* str, int length)
{
    /*
        算法思想
        第一次:i=0(j=1,此时比较str[0],str[1]。如果str[1]比str[0]还小的话,进行交换,此时str[0]是前2个最小值了。接着j=2的时候,也就是第3个元素的时候,在进行比较str[0],str[2]。如果str[2]比str[0]小的话,进行交换。此时str[0]就是前3个最小值了。类推。i=0;执行完的时候第一个元素str[0]一定是所有元素中最小的那一个。这样第一个元素就是有序的。
        第二次:i=1执行过程和i=0类似,只是每次都是和str[1]进行比较了。str[0]是不参与比较的。所以i=1执行完后,str[1]一定是str[1]到str[length-1] 元素的最小值。这样前2个元素是有序的。
        第三次:i=2。这样前3个元素是有序的。
        第N次:i=n-1。 这样前N个元素是有序的。也就是所有元素都是有序的啦。
        总结:每次都是和固定的位置那个元素进行比较。
    */
    assert(str != NULL);
    for (int i = 0; i < length; i++)
    {
        for (int j = i + 1; j < length; j++)
        {
            if (str[i] >str[j])
            {
                Swap(str, i, j);
            }
        }
    }
    return 0;
}

 

冒泡排序

/*冒泡排序*/
int BubbleSort(int* str, int length)
{
    /*
    算法思想
    第一次:i=0(j=0,此时比较str[0],str[1]。如果str[1]比str[0]还小的话,进行交换,此时str[0]是前2个最小值了 str[1]是前2个最大值。接着j=1的时候,在进行比较str[1],str[2]。如果str[2]比str[1]小的话,进行交换。此时str[2]就是前3个最大值了。类推。i=0;执行完的时候最后一个元素str[length-1]一定是所有元素中最大的那一个。这样最后一个元素就是有序的。
    第二次:i=1执行过程和i=0类似,每次相邻元素进行比较。所以i=1执行完后,倒数第二个元素str[length-2]一定是str[0]到str[length-2] 元素的最小值。这样后2个元素是有序的。
    第三次:i=2。这样后3个元素是有序的。
    第N次:i=n-1。 这样后N个元素是有序的。也就是所有元素都是有序的啦。
    总结:每次都是相邻的元素进行比较,可以定义一个flag标示变量前面的结果是否有序进行优化。
    */
    assert(str != NULL);
    for (int i = 0; i < length; i++)
    {
        for (int j = 0; j < length - 1; j++)
        {
            if (str[j] > str[j + 1])
            {
                Swap(str, j, j + 1);
            }
        }
    }
    return 0;
}

 

插入排序

/*插入排序*/
int InsertSort(int* str, int length)
{
    /*
        算法思想
        这里举例个数据    1 , 2 ,4 , 5  , 3 
        核心:就是取出来一个元素,然后和前面的有序序列进行比较,找到合适的位置。插进去,这个位置的后面的需要后移。
        对于上面的这个数组一共5个元素,前4个是有序的。那么怎么讲第5个元素(3)插入到指定位置呢。
         1.取出来: 先用一个变量pos 保存3这个元素的位置下标(pos =4),用一个value保存这个元素的值(3 )。
         2.进行比较: 前面的4个元素(1,2,4,5)是有序的。先将 3和有序序列的最后一个元素(5)进行比较,3是小于5的,那么就将5这个元素放到原来3的为位置上去,这样5的这个位置就空出来了(也就是取出来了 pos =3)在和4进行比较。3小于4的。那么4这个元素后移下。这样pos=2的位置就空出来了。
             3在和2进行比较,3是大于2的,for循环结束 把value(3) 赋值到pos位置上去,也就是str[pos] =value,级str[2] =3;
         3.这样结果就是有效的了。
         当然开始的时候前面几个不是有序的,至少第一个元素是有序的。那么就从第二个元素开始进行插入。也就是i=1开始,i=1结束的时候前面2个元素是有序
         i=2,结束的时候前面3个元素是有序的。i=length -1,结束的时候前面length 个元素都是有序的。也就是整个数组是有序的。
    */
    assert(str != NULL);
    for (int  i = 1; i < length; i++)
    {
        int pos = i;
        int value = str[i];
        for (int  j = i-1; j >=0 && str[j] >value; j--)
        {
            str[j + 1] = str[j];
            pos = j;
        }
        str[pos] = value;

    }
    return 0;
}

 

希尔排序

/*希尔排序*/
int ShellSort(int* str, int length)
{
    /*
        算法思想:
        核心代码和插入排序一样。加入了分组处理,gap=gap/3+1 这样分组是效率最高的。
    */
    assert(str != NULL);
    int gap = length;
    do
    {
        gap = gap / 3 + 1;

        for (int i = gap; i < length; i+=gap)
        {
            int pos = i;
            int value = str[i];
            for (int j = i - gap; j >= 0 && str[j] >value; j-=gap)
            {
                str[j + gap] = str[j];
                pos = j;
            }
            str[pos] = value;

        }


    } while (gap > 1);
    
    return 0;
}

 

快速排序

/*快速排序*/
/*******************************************************************************/
int Partition(int* str, int low, int high)
{
    /*
        函数功能:就是分隔str的low元素到high的元素(一共high-low+1个)比第一个元素(temp=str[low])大的都放到右边,比temp小的都放到左边。
        算法思想:
            这里给一个简单的数组来解释这个函数的功能
            str 的数组元素(7个 low =0 high =6)  8,7,2,4,8,9,2 
            1.取temp =str[low]=8;
            2;low就是第一个元素的下标,high就是最后一个元素的下标。第一次判断str[high] >= temp 为假,交换8和2 此时low =0 high =6数组变成了2,7,2,4,8,9,8 接着判断str[low]<=temp(2<8)为真,low++,此时low =1,high =6 ,接着判断str[low]<=temp(7<8)为真,low++,此时low=2,high=6,接着判断str[low]<=temp(2<8)为真low++,此时low=3,high=6 接着判断str[low]<=temp(4<8)为真low++,此时low=4,high=6,接着判断str[low]<=temp(8<=8)为真low++,low=5,high=6,接着判断str[low]<=temp(9<=8)为假,交换9和8,此时low=5,high=6 数组变成了2,7,2,4,8,8,9,接着进行判断str[high]>=temp(9>=8)为真,high--此时low=5,high=5 ,交换low和high位置元素,其实是一样的。最终返回一个low也就是5,也就是初始的第一个元素现在在这个数组的位置下标啦。最终得到的数组就是2,7,2,4,8,8,9.
    */
    assert(str != NULL);
    int temp = str[low];
    while (low <high)
    {
        while (low <high  && str[high] >= temp)
        {
            high--;
        }
        Swap(str, low, high);
        while (low <high && str[low] <= temp)
        {
            low++;
        }
        Swap(str, low, high);
    }
    return low;
    
}
int QSort(int* str, int low, int high)
{
    /*
        算法思想:
            int par =Partition(str,low,high)执行后返回一个数组下标值par,str数组中数组下标小于par的元素都是小于str[par]的。数组下标大于par的元素都是大于str[par]的。这个时候str[par]就是不会在改变了。
            QSort(str, low, par - 1);就是给low 到par-1的那些元素进行分割,每次都会确定一个str[par]的值不会再去改变的。
        剩下的就是递归调用完成最终的排序计算。
    */
    assert(str != NULL);
    if (low < high)
    {
        int par = Partition(str, low, high);
        QSort(str, low, par - 1);
        QSort(str, par + 1, high);
    }
    return 0;
}
int QuickSort(int* str, int length)
{
    assert(str != NULL);
    return     QSort(str, 0, length - 1);

}

 

归并排序

/*归并排序*/
/*******************************************************************************/
void Merge(int* src, int* dst, int low, int mid, int high)
{
    /*
        归并排序算法思想:
        src1 low到mid是有序的,mid到high是有序的。
        这个函数就是将2个各自有序的数组合成一个数组
        一个数组是1 ,4, 5 ,7  一个数组是2,3 ,6,8,9 10
        第一次判断src[i] <src[j] 即1<2为真 dst[k++] =1;将1赋值到结果数组去i++,k++
        第二次判断src[i] <src[j}}即2<2为假 dst[k++] =2;将2赋值到结果数组去 j++,k++
        最终会有一个数组剩下元素,另一个数组没有元素的。
        将那个数组的元素copy到结果数组中去。

    */
    assert(src != NULL);
    assert(dst != NULL);
    int i = low;
    int j = mid + 1;
    int k = low;
    while (i<=mid && j<=high)
    {
        /*每次插入两个数组的头部最小值到目标数组中,保证了目标数组是有序的*/
        if (src[i] < src[j])
        {
            dst[k++] = src[i++];
        }
        else
        {
            dst[k++] = src[j++];
        }
    }
    /*将剩下的那部分copy到目标数组中去*/
    while (i<=mid)
    {
        dst[k++] = src[i++];
    }
    while (j<=high)
    {
        dst[k++] = src[j++];
    }
}
int  MSort(int* src, int* dst, int low, int high, int max)
{
    assert(src != NULL);
    assert(dst != NULL);
    if (low == high)
    {
        /*只有一个元素的时候直接给目标数组赋值了。不用在递归啦*/
        dst[low] = src[low];
        return 0;
    }
    else
    {
        int mid = (low + high) / 2;
        int *space = (int*)malloc(sizeof(int)* max);
        if (space == NULL)
        {
            return -1;
        }
        //递归调用进行分割直到只有一个元素递归结束
        MSort(src, space, low, mid, max);
        MSort(src, space, mid + 1, high, max);
        //对递归的数据进行合并
        Merge(space, dst, low, mid, high);
        if (space != NULL)
        {
            free(space);
        }
        return 0;
    }
    return 0;
}
int MergeSort(int* str,int length)
{
    assert(str != NULL);
    return MSort(str, str, 0, length - 1, length);

}

 

以上代码汇总

sort.h文件

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _SORT_H_
#define _SORT_H_

#ifdef __cplusplus
extern "C"
{
#endif
    int   __declspec(dllexport)   SelectSort(int* str, int length);
    void  __declspec(dllexport)   PrintArraryElement(int* str, int length);
    int   __declspec(dllexport)   BubbleSort(int* str, int count);
    int   __declspec(dllexport)   InsertSort(int* str, int length);
    int   __declspec(dllexport)   ShellSort(int* str, int length);
    int   __declspec(dllexport)   QSort(int* str, int low, int high);
    int   __declspec(dllexport)   QuickSort(int* str, int length);
    int   __declspec(dllexport)   MergeSort(int* str, int length);

#ifdef __cplusplus
}
#endif

#endif

 

sort.cpp文件

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Sort.h"
#include <assert.h>

/*辅助交换函数*/
int Swap(int* str, int pos1, int pos2)
{
    if (str == NULL)
    {
        return -1;
    }
    if (pos1 < 0 || pos2 < 0)
    {
        return -2;
    }
    /*交换数组pos1的值和pos2的值*/
    int temp = str[pos1];
    str[pos1] = str[pos2];
    str[pos2] = temp;
    return 0;
}
/*打印数组元素*/
void PrintArraryElement(int* str, int length)
{
    
    assert(str != NULL);
    printf("\t\t\t");
    for (int i = 0; i < length; i++)
    {
        printf("%d\t", str[i]);
    }
    printf("\n");

}
/*选择排序*/
int SelectSort(int* str, int length)
{
    /*
        算法思想
        第一次:i=0(j=1,此时比较str[0],str[1]。如果str[1]比str[0]还小的话,进行交换,此时str[0]是前2个最小值了。接着j=2的时候,也就是第3个元素的时候,在进行比较str[0],str[2]。如果str[2]比str[0]小的话,进行交换。此时str[0]就是前3个最小值了。类推。i=0;执行完的时候第一个元素str[0]一定是所有元素中最小的那一个。这样第一个元素就是有序的。
        第二次:i=1执行过程和i=0类似,只是每次都是和str[1]进行比较了。str[0]是不参与比较的。所以i=1执行完后,str[1]一定是str[1]到str[length-1] 元素的最小值。这样前2个元素是有序的。
        第三次:i=2。这样前3个元素是有序的。
        第N次:i=n-1。 这样前N个元素是有序的。也就是所有元素都是有序的啦。
        总结:每次都是和固定的位置那个元素进行比较。
    */
    assert(str != NULL);
    for (int i = 0; i < length; i++)
    {
        for (int j = i + 1; j < length; j++)
        {
            if (str[i] >str[j])
            {
                Swap(str, i, j);
            }
        }
    }
    return 0;
}
/*冒泡排序*/
int BubbleSort(int* str, int length)
{
    /*
    算法思想
    第一次:i=0(j=0,此时比较str[0],str[1]。如果str[1]比str[0]还小的话,进行交换,此时str[0]是前2个最小值了 str[1]是前2个最大值。接着j=1的时候,在进行比较str[1],str[2]。如果str[2]比str[1]小的话,进行交换。此时str[2]就是前3个最大值了。类推。i=0;执行完的时候最后一个元素str[length-1]一定是所有元素中最大的那一个。这样最后一个元素就是有序的。
    第二次:i=1执行过程和i=0类似,每次相邻元素进行比较。所以i=1执行完后,倒数第二个元素str[length-2]一定是str[0]到str[length-2] 元素的最小值。这样后2个元素是有序的。
    第三次:i=2。这样后3个元素是有序的。
    第N次:i=n-1。 这样后N个元素是有序的。也就是所有元素都是有序的啦。
    总结:每次都是相邻的元素进行比较,可以定义一个flag标示变量前面的结果是否有序进行优化。
    */
    assert(str != NULL);
    for (int i = 0; i < length; i++)
    {
        for (int j = 0; j < length - 1; j++)
        {
            if (str[j] > str[j + 1])
            {
                Swap(str, j, j + 1);
            }
        }
    }
    return 0;
}
/*插入排序*/
int InsertSort(int* str, int length)
{
    /*
        算法思想
        这里举例个数据    1 , 2 ,4 , 5  , 3 
        核心:就是取出来一个元素,然后和前面的有序序列进行比较,找到合适的位置。插进去,这个位置的后面的需要后移。
        对于上面的这个数组一共5个元素,前4个是有序的。那么怎么讲第5个元素(3)插入到指定位置呢。
         1.取出来: 先用一个变量pos 保存3这个元素的位置下标(pos =4),用一个value保存这个元素的值(3 )。
         2.进行比较: 前面的4个元素(1,2,4,5)是有序的。先将 3和有序序列的最后一个元素(5)进行比较,3是小于5的,那么就将5这个元素放到原来3的为位置上去,这样5的这个位置就空出来了(也就是取出来了 pos =3)在和4进行比较。3小于4的。那么4这个元素后移下。这样pos=2的位置就空出来了。
             3在和2进行比较,3是大于2的,for循环结束 把value(3) 赋值到pos位置上去,也就是str[pos] =value,级str[2] =3;
         3.这样结果就是有效的了。
         当然开始的时候前面几个不是有序的,至少第一个元素是有序的。那么就从第二个元素开始进行插入。也就是i=1开始,i=1结束的时候前面2个元素是有序
         i=2,结束的时候前面3个元素是有序的。i=length -1,结束的时候前面length 个元素都是有序的。也就是整个数组是有序的。
    */
    assert(str != NULL);
    for (int  i = 1; i < length; i++)
    {
        int pos = i;
        int value = str[i];
        for (int  j = i-1; j >=0 && str[j] >value; j--)
        {
            str[j + 1] = str[j];
            pos = j;
        }
        str[pos] = value;

    }
    return 0;
}
/*希尔排序*/
int ShellSort(int* str, int length)
{
    /*
        算法思想:
        核心代码和插入排序一样。加入了分组处理,gap=gap/3+1 这样分组是效率最高的。
    */
    assert(str != NULL);
    int gap = length;
    do
    {
        gap = gap / 3 + 1;

        for (int i = gap; i < length; i+=gap)
        {
            int pos = i;
            int value = str[i];
            for (int j = i - gap; j >= 0 && str[j] >value; j-=gap)
            {
                str[j + gap] = str[j];
                pos = j;
            }
            str[pos] = value;

        }


    } while (gap > 1);
    
    return 0;
}
/*快速排序*/
/*******************************************************************************/
int Partition(int* str, int low, int high)
{
    /*
        函数功能:就是分隔str的low元素到high的元素(一共high-low+1个)比第一个元素(temp=str[low])大的都放到右边,比temp小的都放到左边。
        算法思想:
            这里给一个简单的数组来解释这个函数的功能
            str 的数组元素(7个 low =0 high =6)  8,7,2,4,8,9,2 
            1.取temp =str[low]=8;
            2;low就是第一个元素的下标,high就是最后一个元素的下标。第一次判断str[high] >= temp 为假,交换8和2 此时low =0 high =6数组变成了2,7,2,4,8,9,8 接着判断str[low]<=temp(2<8)为真,low++,此时low =1,high =6 ,接着判断str[low]<=temp(7<8)为真,low++,此时low=2,high=6,接着判断str[low]<=temp(2<8)为真low++,此时low=3,high=6 接着判断str[low]<=temp(4<8)为真low++,此时low=4,high=6,接着判断str[low]<=temp(8<=8)为真low++,low=5,high=6,接着判断str[low]<=temp(9<=8)为假,交换9和8,此时low=5,high=6 数组变成了2,7,2,4,8,8,9,接着进行判断str[high]>=temp(9>=8)为真,high--此时low=5,high=5 ,交换low和high位置元素,其实是一样的。最终返回一个low也就是5,也就是初始的第一个元素现在在这个数组的位置下标啦。最终得到的数组就是2,7,2,4,8,8,9.
    */
    assert(str != NULL);
    int temp = str[low];
    while (low <high)
    {
        while (low <high  && str[high] >= temp)
        {
            high--;
        }
        Swap(str, low, high);
        while (low <high && str[low] <= temp)
        {
            low++;
        }
        Swap(str, low, high);
    }
    return low;
    
}
int QSort(int* str, int low, int high)
{
    /*
        算法思想:
            int par =Partition(str,low,high)执行后返回一个数组下标值par,str数组中数组下标小于par的元素都是小于str[par]的。数组下标大于par的元素都是大于str[par]的。这个时候str[par]就是不会在改变了。
            QSort(str, low, par - 1);就是给low 到par-1的那些元素进行分割,每次都会确定一个str[par]的值不会再去改变的。
        剩下的就是递归调用完成最终的排序计算。
    */
    assert(str != NULL);
    if (low < high)
    {
        int par = Partition(str, low, high);
        QSort(str, low, par - 1);
        QSort(str, par + 1, high);
    }
    return 0;
}
int QuickSort(int* str, int length)
{
    assert(str != NULL);
    return     QSort(str, 0, length - 1);

}
/*归并排序*/
/*******************************************************************************/
void Merge(int* src, int* dst, int low, int mid, int high)
{
    /*
        归并排序算法思想:
        src1 low到mid是有序的,mid到high是有序的。
        这个函数就是将2个各自有序的数组合成一个数组
        一个数组是1 ,4, 5 ,7  一个数组是2,3 ,6,8,9 10
        第一次判断src[i] <src[j] 即1<2为真 dst[k++] =1;将1赋值到结果数组去i++,k++
        第二次判断src[i] <src[j}}即2<2为假 dst[k++] =2;将2赋值到结果数组去 j++,k++
        最终会有一个数组剩下元素,另一个数组没有元素的。
        将那个数组的元素copy到结果数组中去。

    */
    assert(src != NULL);
    assert(dst != NULL);
    int i = low;
    int j = mid + 1;
    int k = low;
    while (i<=mid && j<=high)
    {
        /*每次插入两个数组的头部最小值到目标数组中,保证了目标数组是有序的*/
        if (src[i] < src[j])
        {
            dst[k++] = src[i++];
        }
        else
        {
            dst[k++] = src[j++];
        }
    }
    /*将剩下的那部分copy到目标数组中去*/
    while (i<=mid)
    {
        dst[k++] = src[i++];
    }
    while (j<=high)
    {
        dst[k++] = src[j++];
    }
}
int  MSort(int* src, int* dst, int low, int high, int max)
{
    assert(src != NULL);
    assert(dst != NULL);
    if (low == high)
    {
        /*只有一个元素的时候直接给目标数组赋值了。不用在递归啦*/
        dst[low] = src[low];
        return 0;
    }
    else
    {
        int mid = (low + high) / 2;
        int *space = (int*)malloc(sizeof(int)* max);
        if (space == NULL)
        {
            return -1;
        }
        //递归调用进行分割直到只有一个元素递归结束
        MSort(src, space, low, mid, max);
        MSort(src, space, mid + 1, high, max);
        //对递归的数据进行合并
        Merge(space, dst, low, mid, high);
        if (space != NULL)
        {
            free(space);
        }
        return 0;
    }
    return 0;
}
int MergeSort(int* str,int length)
{
    assert(str != NULL);
    return MSort(str, str, 0, length - 1, length);

}

 

sortTest.cpp文件

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Sort.h"


int main()
{
    int str1[12] = { 12, 4, 53, 3, 2, 34, 6, 35, 1, 132, 324, 12 };
    int str2[12] = { 12, 4, 53, 3, 2, 34, 6, 35, 1, 132, 324, 12 };
    int str3[12] = { 12, 4, 53, 3, 2, 34, 6, 35, 1, 132, 324, 12 };
    int str4[12] = { 12, 4, 53, 3, 2, 34, 6, 35, 1, 132, 324, 12 };
    int str5[12] = { 12, 4, 53, 3, 2, 34, 6, 35, 1, 132, 324, 12 };
    int str6[12] = { 12, 4, 53, 3, 2, 34, 6, 35, 1, 132, 324, 12 };
    int str7[12] = { 12, 4, 53, 3, 2, 34, 6, 35, 1, 132, 324, 12 };
    printf("打印排序前的原始结果:\n");
    PrintArraryElement(str1, sizeof(str1) / sizeof(*str1));
    /*选择排序*/
    printf("执行选择排序的结果如下:\n");
    SelectSort(str1, sizeof(str1) / sizeof(*str1));
    PrintArraryElement(str1, sizeof(str1) / sizeof(*str1));
    /*冒泡排序*/
    printf("执行冒泡排序的结果如下:\n");
    BubbleSort(str2, sizeof(str2) / sizeof(*str2));
    PrintArraryElement(str2, sizeof(str2) / sizeof(*str2));
    /*插入排序*/
    printf("执行插入排序的结果如下:\n");
    InsertSort(str3, sizeof(str3) / sizeof(*str3));
    PrintArraryElement(str3, sizeof(str3) / sizeof(*str3));
    /*希尔排序*/
    printf("执行希尔排序的结果如下:\n");
    ShellSort(str4, sizeof(str4) / sizeof(*str4));
    PrintArraryElement(str4, sizeof(str4) / sizeof(*str4));
    /*快速排序1*/
    printf("执行快速排序1的结果如下:\n");
    QuickSort(str5, sizeof(str5) / sizeof(*str5));
    PrintArraryElement(str5, sizeof(str5) / sizeof(*str5));
    /*快速排序2*/
    printf("执行快速排序(只排序前6个)的结果如下:\n");
    QSort(str6, 0,5 );
    PrintArraryElement(str6, sizeof(str6) / sizeof(*str6));
    /*归并排序*/
    printf("执行归并排序的结果如下:\n");
    MergeSort(str7, sizeof(str7) / sizeof(*str7));
    PrintArraryElement(str7, sizeof(str7) / sizeof(*str7));



    system("pause");
    return 0;
}

测试运行结果如下

 

 

posted on 2016-01-12 11:43  LinuxPanda  阅读(538)  评论(0编辑  收藏  举报

导航