排序种类及相应思想
①冒泡排序:冒泡排序算法的运作如下:(从后往前)比较相邻的元素。如果第一个比第二个大,就交换他们两个。对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。针对所有的元素重复以上的步骤,除了最后一个。持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
②选择排序:它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。选择排序是不稳定的排序方法(比如序列[5, 5, 3]第一次就将第一个[5]与[3]交换,导致第一个5挪动到第二个5后面)。
③插入排序:插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置),而第二部分就只包含这一个元素(即待插入元素)。在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中。
④二分插入排序:将直接插入排序中寻找A[i]的插入位置的方法改为采用折半比较,即可得到折半插入排序算法。在处理A[i]时,A[0]……A[i-1]已经按关键码值排好序。所谓折半比较,就是在插入A[i]时,取A[i-1/2]的关键码值与A[i]的关键码值进行比较,如果A[i]的关键码值小于A[i-1/2]的关键码值,则说明A[i]只能插入A[0]到A[i-1/2]之间,故可以在A[0]到A[i-1/2-1]之间继续使用折半比较;否则只能插入A[i-1/2]到A[i-1]之间,故可以在A[i-1/2+1]到A[i-1]之间继续使用折半比较。如此担负,直到最后能够确定插入的位置为止。一般在A[k]和A[r]之间采用折半,其中间结点为A[k+r/2],经过一次比较即可排除一半记录,把可能插入的区间减小了一半,故称为折半。执行折半插入排序的前提是文件记录必须按顺序存储。
⑤希尔排序:希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。
各组内的排序通常采用直接插入法。由于开始时s的取值较大,每组内记录数较少,所以排序比较快。随着不断增大,每组内的记录数逐步增多,但由于已经按排好序,因此排序速度也比较快。
⑥归并排序:归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并
⑦堆排序:堆排序是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。
⑧快速排序:它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
一种是比较排序,时间复杂度O(nlogn) ~ O(n^2),主要有:冒泡排序,选择排序,插入排序,归并排序,堆排序,快速排序等。
另一种是非比较排序,时间复杂度可以达到O(n),主要有:基数排序等。
下表展示一下常用的比较排序算法的各种性能
冒泡算法代码实现:
for (int i = 0 ; i < array.Length - 1 ; i++)
{
for (int j = i + 1 ; j < array.Length ; j++)
{
if (array[j] < array[i])
{
temp = array[i] ;
array[i] = array[j] ;
array[j] = temp ;
}
}
}
选择排序代码实现:
for(i=0;i<n;i++)
{ k=i;
for(j=k+1;j<n;j++)
if(a[k]<a[j]) k=j;
temp=a[i];a[i]=a[k];a[k]=temp;
}
插入排序代码实现:
void zjinsert (Redtype r[],int n)
{
int I,j;
Redtype temp;
for (i=1;i<n;i++)
{
temp = r[i];
j=i-1;
while (j>-1 &&temp.key<r[j].key)
{
r[j+1]=r[j];
j--;
}
r[j+1]=temp;
}
}
二分插入代码实现:
for (i = 1; i < length; i++)
{
if (array[i]<array[i - 1])
{
int temp = array[i];
for (j = i - 1; array[j]>temp; j--) //元素后移
{
array[j + 1] = array[j];
}
array[j+1] = temp; //在合适的位置上出入元素
}
}
希尔排序代码实现:
void Shell_Sort(int a[],int n)
{
int i,j,d;
for(d=n/2;d>0;d/=2)
{
for(i=d;i<n;++i)
{
int temp=a[i];
for(j=i;j>=d&&a[j-d]>temp;j-=d)
a[j]=a[j-d];
a[j]=temp;
}
}
}
归并排序代码实现:
void guibing(int A[],int Temp[],int L,int R,int RightEnd)//合并两个有序序列
{
int LeftEnd=R-1;
int p=L,i;
int num=RightEnd-L+1;
while(L<=LeftEnd&&R<=RightEnd)
if(A[L]<=A[R])
Temp[p++]=A[L++];
else
Temp[p++]=A[R++];
while(L<=LeftEnd)
Temp[p++]=A[L++];
while(R<=RightEnd)
Temp[p++]=A[R++];
for(i=0;i<num;i++,RightEnd--)
A[RightEnd]=Temp[RightEnd];
}
void MSort(int A[],int Temp[],int L,int RightEnd)
{
int center;
if(L<RightEnd)
{
center=(L+RightEnd)/2;
MSort(A,Temp,L,center);
MSort(A,Temp,center+1,RightEnd);
Merge(A,Temp,L,center+1,RightEnd);
}
}
void Merge_sort(int A[],int N)
{
int *Temp=(int *)malloc(N*sizeof(int));
if(Temp)
{
MSort(A,Temp,0,N-1);
free(Temp);
}
else
printf("no space!\n");
}
堆排序代码实现:
void HeapAdjust(int H[],int start,int end)//堆调整,将start和end之间的元素调整为最大堆
{
int temp=H[start];
int parent=start,child;
while(2*parent<=end)
{
child=2*parent;
if(child!=end&&H[child]<H[child+1])++child;
if(temp>H[child])break;
else H[parent]=H[child];
parent=child;
}
H[parent]=temp;
}
void HeapSort(int H[],int L,int R)
{
for(int i=(R-L+1)/2;i>=L;--i)//调整整个二叉树为最大堆
HeapAdjust(H,i,R);
for(int i=R;i>=L;--i)
{
swap(&H[L],&H[i]);
HeapAdjust(H,L,i-1);
}
}
快速排序代码实现:
#include "stdio.h"
#include "stdlib.h"
#include "time.h"//用于获取程序运行时间
void quick_sort(int s[],int l,int r)
{
if(l < r)
{
int i=l,j=r,x=s[l];
while(i<j)
{
while(i<j && s[j]>=x)//从右到左找到第一个小于x的数
j--;
if(i<j)
s[i++]=s[j];
while(i<j && s[i]<=x)//从左往右找到第一个大于x的数
i++;
if(i<j)
s[j--]=s[i];
}
s[i]=x;//i = j的时候,将x填入中间位置
quick_sort(s,l,i-1);//递归调用
quick_sort(s,i+1,r);
}
}
int main()
{
clock_t start,finish;
double totaltime;
start=clock();
/****下面为需要运行的主程序****/
int a[] = {1,8,44,77,35,65,78,12,25,455,20,15,45};
int length = sizeof(a)/sizeof(int);//求数组的长度
printf("原序列为: ");
for(int i=0;i<length;i++)
{
printf("%3d",a[i]);
}
quick_sort(a,0,length);
printf("\n排序后的序列为:");
for(int i=0;i<length;i++)
{
printf("%3d",a[i]);
}
/********************************/
finish=clock();
totaltime=(double)(finish-start)/CLOCKS_PER_SEC;
printf("\n程序运行的时间为: %.5f 秒",totaltime);
}