数据结构之---排序

任何涉及到比较的排序算法的最优都是O(logN),这里对很常见的排序算法做一个总结。

1、插入排序

它基于一个事实:位置0到P-1的元素都已经排好序了,所以我们只需要将位置P中的元素插入到合适的位置即可。其运行时间是O(N^2),如果已经有序,则为O(N)。

void insert_sort(elementtype A[],int N)
{
int i,j;
int temp;
for(i=1;i<N;i++)
{
temp=A[i];
for(j=i;j>0;j--)
{
if(A[j-1]>temp)/*一一比较,如果比temp大则往后腾出一个坑来*/
A[j]=A[j-1];
else
break;
}
A[j]=temp;
}
}

2、冒泡排序

这是一个最简单的排序算法,每次比较都将最大的元素放到后面去,所以形象的称为冒泡排序。其运行时间也是O(N^2)

void bubble_sort(elementtype A[],int N)
{
int i,j;
int temp;
for(i=N-1;i>0;i--)
for(j=0;j<i;j++)
{
if(A[j+1]<A[j])
{
temp=A[j+1];
A[j+1]=A[j];
A[j]=temp;
}
}
}
3、希尔排序

希尔排序是改良的插入排序,它的曾量不再是1,而是不断变化。

/*然后是希尔排序,它其实也是一种插入排序,不过所选的增量序列不是1,但最终增量序列必须为1*/
void shell_sort(elementtype A[],int N)
{
int i,j,increment;
int temp;
for(increment=N/2;increment>0;increment/=2)/*插入排序即是increment=1时候的排序*/
for(i=increment;i<N;i++)
{
temp=A[i];
for(j=i;j>increment;j-=increment)
{
if(A[j-increment]>temp)
A[j]=A[j-increment];
else
break;
}
A[j]=temp;
}
}
4、堆排序

之前我们就说过,利用堆的有序性可以用来排序,其花费的时间是O(NlogN)。

/*然后是堆排序,堆排序中我们发现并不需要额外的开辟空间,因为可以将最后一个空位用来填首节点删除的节点,我们建立一个最大堆,一次次删除后便可以得到一个排好序的数组了*/
void heap_sort(elementtype A[],int N)
{
int i;
for(i=N/2;i>=0;i--)
percdown(A,i,N);
for(i=N-1;i>0;i--)/*只需要将首尾节点交换,然后重新调节堆即可*/
{
swap(&A[0],&A[i]);
percdown(A,0,i-1);
}
}

void percdown(elementtype A[],int i,int N)
{
int parent,child;
elementtype temp;
int k;
temp=A[i];
parent=i;
child=2*i+1;
while(child<N)
{
if(child!=N-1&&A[child+1]>A[child])
child++;
if(A[child]>temp)
A[parent]=A[child];
else
break;
parent=child;
child=child*2+1;
}
A[parent]=temp;
}

5、归并排序

归并排序基于一个事实是将两个已经排好序的数组合并到一起,它利用的是一种分治的思想。即左边排好序,右边排好序,将左右归并起来即可。而左右采用的操作和自己是相同的,这个递归的结束条件则是其左边不再小于右边。

*然后是归并排序,归并排序的原理是假设左右两个子序列都已排好序,则只需将它们合并起来即可,这是一种分治的思想*/
void merge_sort(elementtype A[],int N)
{
elementtype *temparray;
temparray=(elementtype*)malloc(sizeof(struct elementtype)*N);
if(temparray==NULL)
fatalerror("no space for merge_sort");
else
{
msort(A,temparray,0,N-1);
free(temparray);
}
}

void msort(elementtype A[],elementtype temparray[],int left,int right)
{
int center;
if(left<center)/*递归结束条件为左边等于右边*/
{
center=(left+right)/2;
msort(A,temparray,left,center);/*将左边排序*/
msort(A,temparray,center+1,right);/*将右边排序*/
merge(A,temparray,left,center+1,right);/*将左右归并,其中排序也体现在里面*/
}
}

void merge(elementtype A[],elementtype temparray[],int lbegin,int rbegin,int rend)
{
int lend=rbegin-1;
int number=rend-lbegin+1;
int temp=lbegin;
while(lbegin<=lend&&rbegin<=rend)
{
if(A[lbegin]>=A[rbegin])
{
temparray[temp++]=A[rbegin++];
}
else
temparray[temp++]=A[lbegin++];
}
while(lbegin<=lend)
temparray[temp++]=A[lbegin++];
while(rbegin<=rend)
temparray[temp++]=A[rbegin++];
int i;
for(i=0;i<number;i++)
A[rend--]=temparray[rend--];
}
归并排序是所有外部排序的基础。

6、快速排序

快排也是一种分治思想的巧妙运用,当然还结合了填坑的思想,这个我们在前面已经应用了很多次了。

/*最后是快排,快排每次选定一个pivot,将数组中所有大于它的元素放到它左边,小于它的放到它右边,然后对左右再分别这样递归*/
/*关键点之一是pivot的选取*/
void quick_sort(elementtype A[],int left,int right)
{
if(left<right)
{
int i=left;
int j=right;
int pivot=A[left];
while(i<j)
{
while(i<j&&A[j]>=pivot)
j--;
if(i<j)
A[i++]=A[j];
while(i<j&&A[i]<=pivot)
i++;
if(i<j)
A[j--]=A[i];
}
A[i]=temp;
}
quick_sort(A,left,i-1);
quick_sort(A,i+1,right);
}

void sort(elementtype A[],int N)
{
quick_sort(A,0,N-1);
}
排序是算法中一个重要的部分,必须牢牢掌握其思想和相关方法。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值