1.插入排序
        基本思想是:每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子表中的适当位置,直到全部记录插入完成为止。常规插入排序分两种,即直接插入排序和希尔排序。
1.1直接插入排序
        假设待排序的记录放在数组R[0...n-1]中,排序过程的某一中间时刻,R被划分成两个子区间R[0..i-1]和R[i..n-1],其中:前一个区间是已经排好序的有序区,后一个子区间是当前未排序的部分,不妨称为无序区。直接插入排序的基本操作是将当前无序区的第一个记录R[i]插入到R[0..i-1]中适当的位置,使R[0..i]变为新的有序区-------算法时间复杂度o(n^2)。

    // 插入排序  
    void insertSort(int array[], int length)  
    {  
        int i, j, key;  
        for (i = 1; i < length; i++)  
        {  
            key = array[i];  
            // 把i之前大于array[i]的数据向后移动  
            for (j = i - 1; j >= 0 && array[j] > key; j--)  
            {  
                array[j + 1] = array[j];  
            }  
            // 在合适位置安放当前元素  
            array[j + 1] = key;  
        }  
    }

1.2shell排序
        希尔排序也是一种插入排序方法,实际上是一种分组插入方法。基本思想是:先取定一个小于n的整数d1作为第一个增量,把表的全部记录分成d1个组,所有距离为d1的倍数的记录放在同一个组中,在各组内进行直接插入排序;然后取第二个增量d2(<d1),重复上述的分组和排序,直至所取的增量dt=1(dt<dt-1<..d2<d1),及所有记录放在同一组中进行直接插入排序为止。算法最好时间复杂度o(nlogn)。

// shell排序  
    void shellSort(int array[], int length)  
    {  
        int key;  
        // 增量从数组长度的一半开始,每次减小一倍  
        for (int increment = length / 2; increment > 0; increment /= 2)  
            for (int i = increment; i < length; ++i)  
            {  
                key = array[i];  
                // 对一组增量为increment的元素进行插入排序  
                for (int j = i - increment; j >= 0 && array[j] > key; j -= increment)  
                {  
                    array[j+increment] = array[j];  
                }  
                // 在合适位置安放当前元素  
                array[j+increment] = key;  
            }  
    }

2.交换排序
          基本思想:两两比较待排序记录的关键字,发现两个记录的次序相反时,即进行交换,直到没有反序的记录为止。
2.1冒泡排序
         基本思想是,通过无序区中相邻记录关键字间的比较和位置的交换,使关键字最小的记录如气泡一般逐渐往上“漂浮”直至“水面”。整个算法是从最后面的记录开始,对每两个相邻的关键字进行比较,且使关键字较小的记录换至关键字较大的记录之上,使得经过一趟冒泡排序后,关键字最小的记录到大最上端,接着,再在剩下的记录中找到关键字次小的记录,并把它换在第二个位置上,依次类推,一直到所有记录都有序为止。算法时间复杂度o(n^2)。

    //冒泡排序  
    void bubble_sort(int a[], int length)  
    {  
        int i, j, tag;  
      
        for(i = length - 1; i > 0; i--)//不断把前面无序区最大元素移到后面有序区  
        {  
            tag = 1;//标志位  
            for(j = 0; j < i; j++)//前面无序区最大元素不断向后移  
            {  
                if(a[j] > a[j + 1])  
                {  
                    a[j] ^= a[j + 1];  
                    a[j + 1] ^= a[j];  
                    a[j] ^= a[j+1];  
                    tag = 0;  
                }  
            }  
            if(tag == 1)  
            {  
                break;  
            }  
        }  
    }

2.2快速排序
         快速排序是由冒泡排序改进而得的,它的基本思想是:在待排序的n个记录中任取一个记录(通常取第一个记录),把该记录放入适当位置后,数据序列被此记录划分成两部分。所有关键字比该记录关键字小的记录放置在前一部分,所有比它大的记录放置在后一部分,并把该记录排在这两部分的中间(称为该记录归位),这个过程称作一趟快速排序。之后对所有的两部分分别重复上述过程,直至每个部分内只有一个记录或为空为止。简单的说,每趟使表的第一个元素放入适当位置,将表一分为二,对子表按递归方法继续这种划分,直至划分的子表长为1或0.-------算法最好时间复杂度o(nlog2n)

 // 对一个给定范围的子序列选定一个枢纽元素,执行完函数之后返回分割元素所在的位置,  
    // 在分割元素之前的元素都小于枢纽元素,在它后面的元素都大于这个元素  
    int partition(int array[], int low, int high)  
    {  
        // 采用子序列的第一个元素为枢纽元素  
        int pivot = array[low];  
        while (low < high)  
        {  
            // 从后往前在后半部分中寻找第一个小于枢纽元素的元素  
            while (low < high && array[high] >= pivot)  
                --high;  
            // 将这个比枢纽元素小的元素交换到前半部分  
            array[low] = array[high];  
            // 从前往后在前半部分中寻找第一个大于枢纽元素的元素  
            while (low < high && array[low] <= pivot)  
                ++low;  
            // 将这个比枢纽元素大的元素交换到后半部分  
            array[high] = array[low];  
        }  
        array[low] = pivot;  
        // 返回枢纽元素所在的位置  
        return low;  
    }  
    // 快速排序  
    void quickSort(int array[], int low, int high)  
    {  
        if (low < high)  
        {  
            int n = partition(array, low, high);  
            quickSort(array, low, n);  
            quickSort(array, n + 1, high);  
        }  
    }

3.选择排序

         基本思想:每一趟从待排序的记录中选出关键字最小的记录,顺序放在已排好序的子表的最后,直到全部记录排序完毕。由于选择排序方法每一趟总是从无序区中选出全局最小(或最大)的关键字,所以适合于从大量的记录中选择一部分排序记录,如,从10000个记录中选择出关键字前10位的记录,就适合使用选择排序法。
3.1直接选择排序
         直接选择排序法:第i趟排序开始时,当前有序区和无序区分别为R[0..i-1]和R[i..n-1](0≤ i≤n-1),该趟排序则是从当前无序区中选出关键字最小的记录R[k],将它与无序区的第一个记录R[i]交换,使得R[0..i]和R[i+1..n-1]分别为新的有序区和新的无序区

 //直接选择排序  
    void selectSort(int array[],int nLength)  
    {  
        int i,j,k;  
        for(i = 0; i < nLength - 1; i++)  
        {  
            k = i;  
            for(j = i+1; j < nLength; j++)  
            {  
                if(array[j] < array[k])  
                    k = j;  
            }  
            if(k != i)  
                swap(&array[k],&array[i]);  
        }  
    }

3.2堆排序
         n个关键字序列Kl,K2,…,Kn称为堆,当且仅当该序列满足如下性质(简称为堆性质):
          (1) ki≤K2i且ki≤K2i+1 或(2)Ki≥K2i且ki≥K2i+1(1≤i≤)
         若将此序列所存储的向量R[1……n]看做是一棵完全二叉树的存储结构,则堆实质上是满足如下性质的完全二叉树:树中任一非叶结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。
         堆的这个性质使得可以迅速定位在一个序列之中的最小(大)的元素。
         堆排序算法的过程如下:1)得到当前序列的最小(大)的元素 2)把这个元素和最后一个元素进行交换,这样当前的最小(大)的元素就放在了序列的最后,而原先的最后一个元素放到了序列的最前面 3)交换可能会破坏堆序列的性质(注意此时的序列是除去已经放在最后面的元素),因此需要对序列进行调整,使之满足于上面堆的性质。重复上面的过程,直到序列调整完毕为止。

// array是待调整的堆数组,i是待调整的数组元素的位置,length是数组的长度  
    void heapAdjust(int array[], int i, int nLength)  
    {  
        int nChild, nTemp;  
        for (nTemp = array[i]; 2 * i + 1 < nLength; i = nChild)  
        {  
            // 子结点的位置是 父结点位置 * 2 + 1  
            nChild = 2 * i + 1;  
            // 得到子结点中较大的结点  
            if (nChild != nLength - 1 && array[nChild + 1] > array[nChild])  
                ++nChild;  
            // 如果较大的子结点大于父结点那么把较大的子结点往上移动,替换它的父结点  
            if (nTemp < array[nChild])  
                array[i] = array[nChild];  
            else// 否则退出循环  
                break;  
        }  
        // 最后把需要调整的元素值放到合适的位置  
        array[i] = nTemp;  
    }  
    // 堆排序算法  
    void heapSort(int array[], int length)  
    {  
        //建立大顶堆  
        for (int i = length / 2 - 1; i >= 0; --i)  
            heapAdjust(array, i, length);  
        // 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素  
        for (int j = length - 1; j > 0; --j)  
        {  
            // 把第一个元素和当前的最后一个元素交换,  
            // 保证当前的最后一个位置的元素都是在现在的这个序列之中最大的  
            swap(&array[0], &array[j]);  
            // 不断缩小调整heap的范围,每一次调整完毕保证第一个元素是当前序列的最大值  
            heapAdjust(array, 0, j);  
        }  
    }

4.归并排序
       归并排序是多次将两个或两个以上的有序表合并成一个有序表。最简单的归并是直接将两个有序的子表合并成一个有序的表。
       两个有序表直接合并成一个有序表的算法Merge().设两个有序表存放在同一数组中相邻的位置上:R[low..mid],R[mid+1..high],先将他们合并到一个局部的暂存数组R1中,待合并完成后将R1复制到R中。每次从两个段中取出一个记录进行关键字的比较,将较小者放入R1中,最后将各段中余下的部分直接复制到R1中。

 void merge(int array[],int start,int mid,int end)  
    {  
        int i,j,k;  
        i = start;  
        j = mid + 1;  
        k = 0;  
        int * p = (int *)malloc((end - start + 1) * sizeof(int));  
      
        while((i <= mid) && (j <= end))  
        {  
            if(array[i] < array[j])  
                p[k++] = array[i++];  
            else  
                p[k++] = array[j++];  
        }  
        while(i <= mid)  
            p[k++] = array[i++];  
        while(j <= end)  
            p[k++] = array[j++];  
      
        k = 0;  
        while(start <= end)  
            array[start++] = p[k++];  
      
        free(p);  
    }  
    //归并排序  
    void mergeSort(int array[],int start,int end)  
    {  
        if(start < end)  
        {  
            int i = (start + end) / 2;  
            mergeSort(array,start,i);  
            mergeSort(array,i+1,end);  
            merge(array,start,i,end);  
        }  
    }

5.计数排序和基数排序     
        在之前介绍过的排序方法,都是属于[比较性]的排序法,也就是每次排序时,都是比较整个关键字的大小以进行排序。计数排序是一个非基于比较的线性时间排序算法。
        计数排序算法的基本思想是对于给定的输入序列中的每一个元素x,确定该序列中值小于x的元素的个数。一旦有了这个信息,就可以将x直接存放到最终的输出序列的正确位置上。例如,如果输入序列中只有17个元素的值小于x的值,则x可以直接存放在输出序列的第18个位置上。

//计数排序  
    //nMaxValue为数组array中最大值  
    void countingSort(int array[],int nMaxValue,int nLength)  
    {  
        int i;  
        int *pTemp = (int *)malloc((nMaxValue + 1) * sizeof(int));  
        int *pResult = (int *)malloc((nLength + 1) * sizeof(int));  
      
        for(i = 0; i <= nMaxValue; i++)  
            pTemp[i] = 0;  
        // 此过程记录每一个元素的个数  
        for(i = 0; i < nLength; i++)  
            pTemp[array[i]]++;  
        // 此过程确定小于元素x的元素的个数  
        for(i = 1; i <= nMaxValue; i++)  
            pTemp[i] += pTemp[i-1];  
        for(i = nLength-1; i >= 0; i--)  
        {  
            pResult[pTemp[array[i]]] = array[i];  
            pTemp[array[i]]--;  
        }  
        for(i = 1; i <= nLength; i++)  
            array[i-1] = pResult[i];  
    }

         基数排序的主要思路是,将所有待比较数值(注意,必须是正整数)统一为同样的数位长度,数位较短的数前面补零. 然后, 从最低位开始, 依次进行一次稳定排序.这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列.
         比如这样一个数列排序: 342 58 576 356, 以下描述演示了具体的排序过程
第一次排序(个位):
3 4 2
5 7 6
3 5 6
0 5 8
第二次排序(十位):
3 4 2
3 5 6
0 5 8
5 7 6
第三次排序(百位):
0 5 8
3 4 2
3 5 6
5 7 6
结果: 58 342 356 576

//基数排序  
    //nMaxBit为数字中的最高位数,如最大数为235,则nMaxBit为3  
    void radixSort(int *array, int nLength ,int nMaxBit)  
    {  
        int i,j;  
        int temp[10];  
        int nTmp;  
        int nRadix = 1;  
        int *pResult = (int *)malloc(nLength * sizeof(int));   
          
        for(j = 1; j <= nMaxBit; j++)  
        {  
            // 以下和计数排序一样  
            for(i = 0; i < 10; i++)  
                temp[i] = 0;  
            // 此过程记录每一个元素的个数  
            for(i = 0; i < nLength; i++)  
            {  
                nTmp = (array[i] / nRadix) % 10;  
                temp[nTmp]++;  
            }  
            // 此过程确定小于元素x的元素的个数  
            for(i = 1; i < 10; i++)  
                temp[i] += temp[i-1];  
            for(i = nLength-1; i >= 0; i--)  
            {  
                nTmp = (array[i] / nRadix) % 10;  
                temp[nTmp]--;  
                pResult[temp[nTmp]] = array[i];  
            }  
            for(i = 0; i < nLength; i++)  
                array[i] = pResult[i];  
            nRadix *= 10;  
        }  
    }