排序算法

来源:互联网 发布:汪正扬看的编程书 编辑:程序博客网 时间:2024/04/27 02:42

冒泡排序:

for(int i=0;i<n-1;i++)
    {
        for(int j=n-1;j>i;j--)
        {
            if(a[j-1]>a[j])
            {
                int tmp=a[j];
                a[j]=a[j-1];
                a[j-1]=tmp;
            }
        }
  }

选择排序:

for(i=0;i<num-1;++i)
    {
        int min=INF,m=i;
        for(int j=i;j<num;++j)
        {
            if(a[j]<min)
            {
                min=a[j];
                m=j;
            }
        }
        int tmp=a[m];
        a[m]=a[i];
        a[i]=tmp;
    }

插入排序:

    int tmp;
    for(int i=1;i<num;i++)
    {
        tmp=a[i];
        int j=i-1;
        while(j>=0&&a[j]>tmp)
        {
            a[j+1]=a[j];
            j--;
        }
        a[j+1]=tmp;
    }

快速排序:

思路:找一个关键数字key=a[i],从右端找一个小于它的数字a[j],a[i]=a[j],从左端找一个大于他的数字a[i],a[j]=a[i],a[i]=key。进行多次,直到i=j,使得左边的数字都小于key,右边的数字都大于key。

int a[MAXN];

void sort(int begin,int end)
{
    if(begin>=end)
        return ;
    int i=begin,j=end,key=a[i];
    while(i<j)
    {
        while(a[j]>=key&&i<j)
        {
            j--;
        }
        a[i]=a[j];
        while(i<j&&a[i]<=key)
        {
            i++;
        }
        if(i<j)
        {
            a[j]=a[i];
        }
    }
    a[i]=key;

    sort(begin,i-1);
    sort(i+1,end);
}

二分归并排序:

思路:将数组分成两份分别排序Mergesort(),然后再合并Merge()。

int a[2*MAXN];
int num;
void Merge(int a[],int begin,int mid, int end)
{

    //用两个数组复制数组的两部分。
    int left[MAXN];
    int right[MAXN];
    int n1=mid-begin+1,n2=end-mid;

    for(int i=0; i<n1; i++)
    {
        left[i]=a[begin+i];
    }
    for(int i=0; i<n2; i++)
    {
        right[i]=a[mid+i+1];
    }
    //注意k是从begin开始,意思比较两个数组的大小,小的排前面。
    int i=0,j=0,k=begin;
    while(i<n1&&j<n2)
    {
        if(left[i]<right[j])
        {
            a[k++]=left[i++];
        }
        else
            a[k++]=right[j++];
    }

    //可能有剩余,直接复制
    for(; i<n1; i++)
        a[k++]=left[i];
    for(; j<n2; j++)
        a[k++]=right[j];
}
void Mergesort(int a[],int begin,int end)
{
    int mid;
    if(begin<end)//至少有2个元素,否则不用排序。
    {
        mid=(begin+end)/2;

//两部分分别排序
        Mergesort(a,begin,mid);
        Mergesort(a,mid+1,end);

//合并
        Merge(a,begin,mid,end);
    }
}

堆排序:

  堆排序是一种选择排序。是不稳定的排序方法。时间复杂度为O(nlogn)。

  堆排序的特点是:在排序过程中,将排序数组看成是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲节点和孩子节点之间的内在关系,在当前无序区中选择关键字最大(或最小)的记录。

堆的定义:     

      n个关键字序列Kl,K2,…,Kn称为堆,当且仅当该序列满足如下性质(简称为堆性质):

      (1)ki<=k(2i+1)且ki<=k(2i+2)(1≤i≤ n),当然,这是小根堆,大根堆则换成>=号。 //ki相当于二叉树的非叶结点,K2i则是左孩子,k2i+1是右孩子  

      若将此序列所存储的向量R[1..n]看做是一棵完全二叉树的存储结构,则堆实质上是满足如下性质的完全二叉树:

     树中任一非叶结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。


堆排序基本思想:

  1.将要排序的数组创建为一个大根堆。大根堆的堆顶元素就是这个堆中最大的元素。

  2.将大根堆的堆顶元素和无序区最后一个元素交换,并将无序区最后一个位置例入有序区,然后将新的无序区调整为大根堆。重复操作,无序区在递减,有序区在递增。

完全二叉树的基本性质:

  数组中有n个元素,i是节点,1 <= i <= n/2 就是说数组的后一半元素都是叶子节点。

     i的父节点位置:i/2

     i左子节点位置:i*2

     i右子节点位置:i*2 + 1

代码:

void build_max_heap(int data[],int datasize)//构建大顶堆
{
    for(int i=datasize-1;i>0;--i)//只有一个元素不用处理
    {
        int parent=i/2,child=i;
        if(data[i]<data[i-1])//选择最大的那个子节点
        child--;
        if(data[child]>data[parent])
        {
            int tmp=data[parent];
            data[parent]=data[child];
            data[child]=tmp;
        }
    }
}
void heap_sort(int data[],int datasize)//构建大顶堆,然后将最后一个元素与第一个元素互换。
{
    for(int i=datasize;i>0;--i)
    {
        build_max_heap(data,i);
        int tmp=data[i-1];
        data[i-1]=data[0];
        data[0]=tmp;
    }
}