各种排序算法

来源:互联网 发布:洛奇英雄传捏脸数据 编辑:程序博客网 时间:2024/06/07 09:37
#include "stdafx.h"
#include "iostream"
using namespace std;
 
// 排序算法大总结
 
// 共用函数声明
void output_array(int data[], int n);
void exchange(int *a, int *b);
 
 
//////////////////////////////////////////////////////////////////////////////////////////
 
// 插入
// 核心思想:把后面的元素插入到前面已经排好的数组中;所谓插入,向前比大小,若比该元素大,后移,直到找到它该去的位置
// 时间复杂度O(N^2);空间复杂度O(1);不稳定
void InsertSort(int *data, int len)
{
    for (int i=1; i<len; i++)
    {
        int key = data[i];
        int j = i -1;
        while(key<data[j])
        {
            data[j+1] = data[j];
            j--;
        }
        data[j+1] = key;
    }
}
 
// 希尔:插入的一种
// http://www.cnblogs.com/nokiaguy/archive/2008/05/16/1199359.html
 
/* 先取一个正整数d1<n,把所有序号相隔d1的数组元素放一组,组内进行直接插入排序;
然后取d2<d1,重复上述分组和排序操作;直至di=1,即所有记录放进一个组中排序为止*/
/*
假设待排序文件有个记录,其关键字分别是:  
49,,,,,,,,,。  
增量序列的取值依次为:  ,,
初始:d=5   38 65 97 76 13 27 49* 55 04
49 13   |-------------------| 
38 27   |-------------------|   
65 49*  |-------------------|   
97 55   |-------------------|   
76 04   |-------------------|   
一趟结果  27 49* 55 04 49 38 65 97 76   
d=3   27 49* 55 04 49 38 65 97 76   
13 55 38 76   |------------|------------|------------|   
27 04 65   |------------|------------|   
49* 49 97   |------------|------------|   
二趟结果  04 49* 38 27 49 55 65 97 76   
d=1   04 49* 38 27 49 55 65 97 76   
|----|----|----|----|----|----|----|----|----|  
三趟结果  13 27 38 49* 49 55 65 76 97 
*/
 
// 时间复杂度O(N^2);空间复杂度O(1);不稳定
 
void ShellSortSub(int data[], int n, int increment) //data表示某分组的起始元素
{
    for(int i=increment; i < n; i += increment) // i表示该组的元素数目
    {
        for(int j=i; j >= increment && data[j] < data[j - increment]; j -= increment)
        {
            exchange(&data[j], &data[j - increment]);
        }
    }
}
 
void ShellSort(int *data, int len)
{
    for(int i=len/2; i>2; i/=2) // 增量规则;len/2,也可以是其他的
    {
        for(int j=0; j<i; j++)  //分组的数目
        {
            ShellSortSub(data + j, len - j, i);
        }
    }
 
    ShellSortSub(data, len, 1);
}
 
//////////////////////////////////////////////////////////////////////////////////////////
 
// 选择
// 核心思想:从某位置向右找,找到最小的元素,将二者位置交换;即一次次选最小,直到排序排好
// 时间复杂度O(N^2);空间复杂度O(1);不稳定
 
int FindMin(int *data, int begin, int end); //子函数
 
void SelectSort(int *data, int len)
{
    for (int i=0; i<len; i++)
    {
        int k = FindMin(data, i, len-1);
        if (k!=i)
        {
            exchange(data+k, data+i);
        }
    }
}
 
int FindMin(int *data, int begin, int end)
{
    int min = data[begin];
    int index = begin;
    for (int i=begin+1; i<=end; i++)
    {
        if (data[i]<min)
        {
            min = data[i];
            index = i;
        }
    }
    return index;
}
 
//////////////////////////////////////////////////////////////////////////////////////////
 
// 合并
// 核心思想:利用归并的思想,将数组对半分,再分,直到每个小数组中只有一个元素;再合并,合并时,判断大小,像扑克牌一样,(*^__^*) ……
// 时间复杂度O(N*logN);空间复杂度O(N)___?;稳定
 
void Merge(int *data, int p, int q, int r); // SubFunction
 
void MergeSort(int *data, int p, int r) //p:起始位置,r:结束位置
{
    if (p<r)
    {
        int q = (p + r)/2; 
        MergeSort(data, p, q);
        MergeSort(data, q+1, r);
        Merge(data, p, q, r); // 合并
    }
}
 
void Merge(int *data, int p, int q, int r)
{
    int n1 = q-p+1;
    int n2 = r-q;
 
    int *Left = new int[n1];
    int *Right = new int[n2];
 
    for (int i=p; i<=q; i++)
    {
        Left[i-p] = data[i];
    }
    for (int i=q+1; i<=r; i++)
    {
        Right[i-q-1] = data[i];
    }
 
    // 就像两沓子已经排好序扑克牌,对其进行合并排序
    int p1=0; //标记Left 
    int p2=0; //标记Right
    int index = 0; //标记原数组
    for (index=p; index<=r && p1<n1 && p2<n2; index++)
    {
        if (Left[p1] <= Right[p2])
        {
            data[index] = Left[p1];
            p1++;
        }
        else
        {
            data[index] = Right[p2];
            p2++;
        }
    }
 
    // Left 或Right仍有剩余
    while(p1<n1)
    {
        data[index++] = Left[p1++];
    }
 
    while(p2<n2)
    {
        data[index++] = Right[p2++];
    }
 
 
    delete []Left;
    delete []Right;
}
 
 
//////////////////////////////////////////////////////////////////////////////////////////
 
// 冒泡
// 核心思想:把数组看成气泡,只能轻的在重的智商
// 时间复杂度O(N^2);空间复杂度O(1);不稳定
void BubbleSort(int *data, int len)
{
    for (int i=0; i<len; i++)
    {
        for (int j=len-1; j>i; j--)
        {
            if (data[j]<data[j-1])
            {
                exchange(data+j, data+j-1);
            }
        }
    }
}
 
//////////////////////////////////////////////////////////////////////////////////////////
 
// 堆排序
// 核心思想:建最大堆,取根元素,放在数组末尾(将原尾元素与根元素交换),然后重建堆
// 时间复杂度O(N*logN);空间复杂度O(1);不稳定
 
int left(int i);
int right(int i);
int parent(int i);
void MaxHeapify(int *data, int len, int i);
void BuildMaxHeap(int *data, int len);
 
void HeapSort(int *data, int len)
{
    BuildMaxHeap(data, len);
    for (int i=len-1; i>=0; i--)
    {
        exchange(data, data+i);
        len--;
        MaxHeapify(data, len, 0);
    }
}
 
void BuildMaxHeap(int *data, int len)
{
    for (int i=len/2-1; i>=0; i--)
    {
        MaxHeapify(data, len, i);
    }
}
 
void MaxHeapify(int *data, int len, int i) // 关键函数:建立以i为根的最大堆
{
    int L = left(i);
    int R = right(i);
    int largest = 0;
 
    if (L<len && data[L]>data[i])
    {
        largest = L;
    }
    else
    {
        largest = i;
    }
 
    if (R<len && data[R]>data[largest])
    {
        largest = R;
    }
 
    if (largest!=i)
    {
        exchange(data+i, data+largest);
        MaxHeapify(data, len, largest);
    }
}
 
int left(int i)
{
    return 2*i;
}
 
int right(int i)
{
    return 2*i+1;
}
 
int parent(int i)
{
    return i/2;
}
 
//////////////////////////////////////////////////////////////////////////////////////////
 
// 快排(两种)
// 核心思想:将末尾的元素放在它该放的位置——靠两个指针实现。使它之前的元素小于它,之后的大于它。子数组重复
// 时间复杂度O(N*logN);空间复杂度O(1);不稳定
 
int Partition(int *data, int p, int r);
 
void QuickSort(int *data, int p, int r)// p:起始位置r:末尾位置
{
    if (p<r)
    {
        int q = Partition(data, p, r); // 核心函数
        QuickSort(data, p, q-1);
        QuickSort(data, q+1, r);
    }
}
 
int Partition(int *data, int p, int r)
{
    int key = data[r];
    int i=p-1; // 第一个标记:存放小于key的元素的末位置
    for (int j=p; j<r; j++)
    {
        if (data[j]<=key)
        {
            i++;
            exchange(data+i, data+j);
        }
    }
    exchange(data+i+1, data+r);
    return i+1;
}
/*
还有一种想法是这样的:
1)设置两个变量I、J,排序开始的时候:I=0,J=N-1;  
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];  
3)从J开始向前搜索,即由后开始向前搜索(J=J-1),找到第一个小于key的值A[J],并与key交换;  
4)从I开始向后搜索,即由前开始向后搜索(I=I+1),找到第一个大于key的A[I],与key交换;  
5)重复第、、步,直到I=J;(3,4步是在程序中没找到时候j=j-1,i=i+1,直至找到为止。
找到并交换的时候i,j指针位置不变。另外当i=j这过程一定正好是i+或j-完成的最后另循环结束。) 
*/
 
//////////////////////////////////////////////////////////////////////////////////////////
 
// 计数排序
/* 对元素有限定条件:所有元素都小于K
用K大的数组标记每个元素出现的次数,再累加;
对数组进行重置,即已经知道有多少个元素在它前面
*/
// 时间复杂度O(N);空间复杂度O(len*K);稳定
void CountingSort(int *data, int len, int K)
{
    int *newData = new int[len];
    int *C = new  int[K];
    memset(C, 0, sizeof(int)*(K+1));
 
    for (int i=0; i<len; i++)
    {
        int v = data[i];
        newData[i] = v;
        C[v]++;
    }
 
    for (int j=1; j<=K; j++)
    {
        C[j] += C[j-1];
    }
 
    for (int i=len-1; i>=0; i--)
    {
        int v = data[i];
        newData[C[v]-1] = data[i];
        C[v]--;
    }
 
    for (int i=0; i<len; i++)
    {
        data[i] = newData[i];
    }
 
    delete []newData;
}
 
 
//////////////////////////////////////////////////////////////////////////////////////////
 
// 基数排序
// 核心思想:k个计数排序
// 时间复杂度O(k*N);稳定
// 代码就略了。。。
 
 
//////////////////////////////////////////////////////////////////////////////////////////
 
// 桶排序
// 前提:已知元素在一定的区间,且符合均匀分布
// 核心思想:把区间分成n个大小相同的子区间,先对各个桶进行排序,然后依次输出即可
 
// 参考:http://hi.baidu.com/tzpwater/blog/item/5ef60d5a3ec24f9d810a1875.html
 
class element            //element 
{
public:
    int value;
    element *next;
    element()
    {
        value=NULL;
        next=NULL;
    }
};
 
class bucket           //bucket containing a  range of values    
{
public:
    element *firstElement;
    bucket()
    {
        firstElement = NULL;
    }
};
 
void BucketSort(int *data, int len, int lowend, int highend)
{
    int *array = data;
 
    int interval=10;;      //number of intervals    
 
    const int noBuckets=(highend-lowend)/interval; //number of buckets required 
    bucket *buckets=new bucket[noBuckets];             
    bucket *temp;
 
    for(int a=0;a<noBuckets;a++)   //creation of required buckets    
    {
        temp=new bucket;
        buckets[a]=*temp;
    }
 
    for(int j=0;j<len;j++)   //sending elments into appropriate buckets
 
    {
        element *temp,*pre;
        temp=buckets[array[j]/interval].firstElement;
        if(temp==NULL)//if it is the first element of the bucket
        {
            temp=new element;
            buckets[array[j]/interval].firstElement=temp;
            temp->value=array[j];
        }
        else
        {
            pre=NULL;
            while(temp!=NULL)     //move till the appropriate position in the bucket
            {
                if(temp->value>array[j])
                    break;
                pre=temp;
                temp=temp->next;
            }
            if(temp != NULL && temp->value>array[j]) //if the new value is in betwen or at the begining
            {
                if(pre==NULL)  //insertion at first if the bucket has elements already
                {
                    element *firstNode;
                    firstNode=new element();
                    firstNode->value=array[j];
                    firstNode->next=temp;
                    buckets[array[j]/interval].firstElement=firstNode;
                }
                else  //insertion at middle
                {
                    element *firstNode;
                    firstNode=new element();
                    firstNode->value=array[j];
                    firstNode->next=temp;
                    pre->next=firstNode;
                }
            }
            else// if the new value is to be created at last of bucket
            {
                temp=new element;
                pre->next=temp;
                temp->value=array[j];
            }
        }
    }
 
 
    // sort
    int index = 0;
    for(int jk=0;jk<10;jk++)
    {
        element *temp;
        temp= buckets[jk].firstElement;
        while(temp!=NULL)
        {
            data[index] = temp->value;
            index++;
            temp=temp->next;
        }
    }
 
    delete []buckets;
}
//////////////////////////////////////////////////////////////////////////////////////////
 
 
int main()
{
    ///////////////////////////////////////////////////////////////////
    int data[] = {49,38,65,97,76,13,27,49,55,04};
 
    //InsertSort(data, 10);
    //ShellSort(data, 10);
    //SelectSort(data, 10);
    //MergeSort(data, 0, 9);
    //BubbleSort(data, 10);
    //HeapSort(data, 10);
    //QuickSort(data, 0, 9);
 
    //output_array( data, 10);
 
    ////////////////////////////////////////////////////////////
 
    //int data2[] = {3,4,5,1,2,3,3,4,2,3};
    //CountingSort(data2, 10, 5);
    //output_array( data2, 10);
 
    ////////////////////////////////////////////////////////////////////
 
    int data3[] = {12,2,22,33,44,55,66,77,85,87,81,83,89,82,88,86,84,88,99};
    BucketSort(data3, 19, 0, 100);
    output_array( data3, 19);
 
    return   0; 
}
 
 
void output_array(int data[], int n)
{
    int i;
    for(i = 0; i < n; i++)
    {
        printf("%d ", data[i]);
    }
    printf("\n");
}
 
void exchange(int *a, int *b)
{
    int x;
    x = *a;
    *a = *b;
    *b = x;
}

0 0