排序算法
来源:互联网 发布:汪正扬看的编程书 编辑:程序博客网 时间: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;
}
}