您的位置:首页 > 其它

八种排序程序总结,已经稳定性,算法复杂度,程序保证正确

2011-03-16 14:09 337 查看
1.直接插入排序

其实就是查找最小,然后顺序一个移动,然后插入;

实现:

void insert(int L[10],int length)

{

int i,j;

int x;

for (i=1;i<length;i++)

{

x=L[i];

j=i-1;

while (x<L[j]&&j>=0)

{

L[j+1]=L[j];

j--;

}

L[j+1]=x;

}

}

这个算法感觉书上说的问题,网上的算法感觉也不靠谱,貌似不对,我就直接拿掉了L[0]那个做监视用的元素,这样直接查找插入反而更加简单些~

///////////////////////////////////////////////////////////////////////////////////////////////////////

2.shell排序

基本思想:
先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为dl的倍数的记录放在同一个组中。先在各组内进行直接插人排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
 该方法实质上是一种分组插入方法。

所以这里就不说了,分个组再插入吧。

////////////////////////////////////////////////////////////////////////////////////////////////////

3,冒泡排序

原理:将序列划分为无序和有序区,不断通过交换较大元素至无序区尾完成排序。

要点:设计交换判断条件,提前结束以排好序的序列循环。

void BubbleSort(int L[])

{

int i ,j,k;

int ischanged,temp; //设计跳出条件

for(j=length;j>0;j--)

{

ischanged =0;

for(i=0;i<j;i++)

{

if(L[i]>L[i+1])//如果发现较重元素就向后移动

{

temp=L[i];

L[i]=L[i+1];

L[i+1]=temp;

ischanged =1;

}

}

if(!ischanged)//若没有移动则说明序列已经有序,直接跳出

break;

}
}

冒泡算法是很很常用的一种算法,想法简单,就是不停的交换交换什么的

//////////////////////////////////////////////////////////////////////////////////////////

以上三种排序都是和数列初始状态有关系的,也就是传说中的关键字比较的次数与记录的初始排列次序有关

//////////////////////////////////////////////////////////////////////////////////////////

4.快速排序

原理:不断寻找一个序列的中点,然后对中点左右的序列递归的进行排序,直至全部序列排序完成,使用了分治的思想。分治法的基本思想是:将原问题分解为若干个规模更小但结构与原问题相似的子问题。递归地解这些子问题,然后将这些子问题的解组合为原问题的解。

要点:递归、分治

实现:

void QuickSort(int R[],int low,int high)

{ //对R[low..high]快速排序

int mid; //划分后的基准记录的位置

if(low<high)

{ //仅当区间长度大于1时才须排序

mid=partitions(R,low,high); //对R[low..high]做划分

QuickSort(R,low,mid-1); //对左区间递归排序

QuickSort(R,mid+1,high); //对右区间递归排序

}

} //QuickSort

int partitions(int a[],int low,int high)

{

int mid=a[low];

int i; //a[0]=a[low];

while(low<high)

{

while(low<high && a[high]>=mid)

--high;

a[low]=a[high];

while(low<high && a[low]<=mid)

++low;

a[high]=a[low];

}

a[low]=mid;

return low;

}

无论适用哪一种方法来选择mid,由于我们不知道各个元素间的相对大小关系(若知道就已经排好序了),所以我们无法确定mid的选择对划分造成的影响。因此对各种mid选择法而言,最坏情况和最好情况都是相同的。我们从直觉上可以判断出最坏情况发生在每次划分过程产生的两个区间分别包含n-1个元素和1个元素的时候(设输入的表有n个元素)。

/////////////////////////////////////////////////////////////////////////////////////////////////////////

5.直接选择排序

原理:将序列划分为无序和有序区,寻找无序区中的最小值和无序区的首元素交换,有序区扩大一个,循环最终完成全部排序。

实现:

void SelectSort(int L[],int length)

{

int i,j,k; //分别为有序区,无序区,无序区最小元素指针

for(i=0;i<length;i++)

{

k=i;

for(j=i+1;j<length;j++)

{

if(L[j]<L[k])

k=j;

}

if(k!=i)//若发现最小元素,则移动到有序区

{

int temp=L[k];

L[k]=L[i];

L[i]=temp;

}

}

}这种哦你算法相对简单的多,不过他需要n-1趟排序,无论状态如何,每一趟排序都要进行n-i趟比较,所以其算法复杂度为O(n×n);直接排序也是不稳定的,之前的shell排序也是不稳定的,简单的说就是如果有两个相同的元素那么他们两个会交换位置。此外还有堆排序、快速排序都是不稳定的。

////////////////////////////////////////////////////////////////////////////////////////////////

6归并排序

原理:将原序列划分为有序的两个序列,然后利用归并算法进行合并,合并之后即为有序序列。也叫2路归并排序~那么关键是首先应该把原表分成两个有序的表,譬如前五个和后五个,然后内部调整其顺序,然后将两个有序表进行对比,首先是比较第一个元素,小的放进新数组的第一个,然后把少元素的顺序前移(可能不需要),然后再对比第一个元素再往新的数组里面放,最后合并到一个数组里面。算法复杂度小于直接选择排序,但是代码量却变大了,其复杂度为O(n*log2 n)。

//////////////////////////////////////////////////////////////////////////////////////////////////////

7基数排序

首先基数排序是稳定的,中心思想是先分配再收集,收集好了再排序,比如像是吧52张牌先按照花色分开,内部排序,然后再按照花色顺序组合。在数字中方法比如是:首先按照个位排序,同样的个位的数放在链表里面,然后再按照十位排序,百位排序,然后就拍好了。其算法复杂度为O(n+radix);radix代表:假设一个数可以拆成d位每一位的取值范围就是radix。整个排序需要d趟分配和收集。

//////////////////////////////////////////////////////////////////////////////////////////////////////

8堆排序

原理:利用大根堆或小根堆思想,首先建立堆,然后将堆首与堆尾交换,堆尾之后为有序区。初建堆的过程是:首先把待排序的所有排序吗表示成一颗完全二叉树,。由完全二叉树的性质可知,所有i>n/2-1的节点ki是叶子节点,以这些节点为根的子树已经是堆,然后从i>n/2-1的节点ki开始,逐个吧以kn/2-1,kn/2-2,...k0为根的自述调整成堆,当以根的二叉树已经调整成堆时,就完成了初建堆的过程.

要点:把排序的数列变成一个二叉树,然后把这个二叉树调成一个堆,填完了后从根节点开始抽出来,因为堆的特点是父节点总是小的。

实现:

void main()

{

void sift(int [],int,int);

void heapsort(int [],int);

int R[10]={25,9,89,21,43,14,100,14,60,78};

int i;

heapsort(R,10);

for (i=0;i<10;i++)

{

printf("%d, ",R[i]);

}

}

void sift(int L[],int t,int w)

{//用筛选法调整堆

int i,j;

int x;

i=t;

x=L[i];

j=2*i+1;

while (j<=w)

{

if((j<w)&&(L[j]>L[j+1]))

j++;

if (x>L[j])

{

L[i]=L[j];i=j;j=2*j+1;

}

else break;

}

L[i]=x;

}

void heapsort(int L[],int n)

{//堆排序算法

int i;

int x;

for (i=n/2-1;i>=0;i--)

sift(L,i,n-1);

for (i=n-1;i>0;i--)

{

x=L[0];L[0]=L[i];L[i]=x;

sift(L,0,i-1);

}

}

堆排序也是不稳定的~

///////////////////////////////////////////////////////////////////////

下面对各个排序方法进行下总结:

1,如果排序的记录个数n比较小,一般小于50,那么使用冒泡,直接选择,直接插入最简单。

2.若n交大,则应该采用归并,快排,或者堆排序。当待排序吗是随机数据时,快速排序的平均运行时间最短,但是堆排序只需要一个记录的辅助空间。并且不会出现快速排序可能出现的最坏情况。这两个方法都是不稳定的排序方法,利用归并能满足稳定性的要求,它通常可与插入排序结合一起使用,即先利用直接插入排序得到多个长度小于50的子序列,然后多趟归并。

3.若待排序记录已按排序码基本有序,则应该采用直接插入排序或起泡排序

4.当n很大且记录本身较大时,可先提取排序吗建立索引表,索引项由排序吗和链域组成,链域存放记录的位置。先对索引表进行排序
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: