/*--------------
author:cqkxboy168
date:2014-8-4
--------------*/
#include <stdio.h>
#include <stdlib.h>
//bitmap使用
#define MAX 200
int map[1+MAX/32]={0};
void swap(int *a,int *b)
{
int temp=*b;
*b=*a;
*a=temp;
}
//选择排序:
//原理:{有序}[无序],每一次循环从[无序]里面Select一个最小的元素。
void SelectSort(int array[],int len)
{
int i,j,temp,flag;
for(i=0;i<len-1;i++)
{
temp=array[i];//i是{有序}的结束下标
flag=i;
for(j=i+1;j<len;j++)//j的起始值是[无序]的首元素.循环结束后flag是最小值的位置,temp是最小值
{
if(array[j]<temp)
{
temp=array[j];//重置temp
flag=j;
}
}
if(flag!=i)
{
array[flag]=array[i];//最小记录与{有序}的最后一个交换位置
array[i]=temp;
}
}
}
//插入排序
//原理:{有序}[无序],选取[无序]的第一个元素insert到{有序}应该的位置
void InsertSort(int array[],int len)
{
int i,j,temp;
for(i=1;i<len;i++) //i控制[无序]循环,注意此处下标为i=1
{
temp=array[i];//[无序]的第一元素
for(j=i-1;j>=0;--j) //j控制{有序} 循环,所以j的开始下标为j=i-1
{
if(temp<array[j])
{
array[j+1]=array[j];
}
else
break;//跳出的位置j的后面就应该是插入的位置
}
array[j+1]=temp;
}
}
//冒泡排序
//原理:相邻元素比较,每一趟选出最大的气泡
void BubbleSort(int array[],int len)
{
int i,j;
for(i=0;i<len;i++)
{
for(j=0;j<len-i;j++)//从len-i中选出最大的值
{
if(array[j]>array[j+1]) //相邻元素比较
swap(&array[j],&array[j+1]);
}
}
}
//归并排序
//原理:递归地把数组折半,当数组只有1个元素时有序,再合并这些有序数组
//合并数组array[frist...mid]和array[mid+1...last]
void Merge(int array[],int frist,int mid,int last)
{
int i=frist,j=mid+1,k=0;
int *temp=(int*)malloc(sizeof(int)*last);
while(i<=mid && j<=last)
{
if(array[i]<array[j])
{
temp[k++]=array[i++];
}
else
{
temp[k++]=array[j++];
}
}
while(i<=mid)
temp[k++]=array[i++];
while(j<=last)
temp[k++]=array[j++];
for(i=0;i<k;i++)
array[frist+i]=temp[i];
}
void MergeSort(int array[],int frist,int last)
{
if(frist<last)
{
int mid=(frist+last)/2;
MergeSort(array,frist,mid);
MergeSort(array,mid+1,last);
Merge(array,frist,mid,last);
}
}
//快速排序
//原理:选定支点,通过一趟排序,比支点小都在其左边,比支点大的都在其右边。然后对前半部分和后半部分递归操作,直到数组只有1个元素
void QuickSort(int array[],int frist,int last)
{
if(frist>=last) //递归结束条件,没有这句程序运行错误
return;
int i=frist,j=last;
int index=array[frist];//支点
while(i<j)
{
while(i<j && array[j]<=index) //从右往左找到第一个小于支点的值
j--;
if(i<j)
array[i++]=array[j];//往左区间填值
while(i<j && array[i]>=index) //从左往右找到第一个大于支点的值
i++;
if(i<j)
array[j--]=array[i];//往右区间填值
}
array[i]=index;//左右区间都填好了,填入支点值
QuickSort(array,frist,i-1);//对左区间递归调用,此刻i=j是支点的位置
QuickSort(array,i+1,last);
}
//希尔排序
//原理:将元素分成多个子序列,对各个子序列进行插入排序
void ShellSort(int array[],int len)
{
int i,j,k,temp;
for(k=len/2;k>0;k=k/2)//按步长值划分为多个子序列
{
for(i=k;i<len;i++)//子序列插入排序
{
temp=array[i];
for(j=i-k;j>=0;j-=k)
{
if(temp<array[j])
{
array[j+k]=array[j];
}
else
break;//j为插入点
}
array[j+k]=temp;
}
}
}
//堆排序
void AdjustMaxHeap(int array[],int pos,int len)
{
int child;
for(;2*pos+1<len;pos=child)
{
child=pos*2+1;//父节点为pos,则左孩子节点为pos*2+1
//得到子节点较大者
if(child<len-1 && array[child+1]>array[child])
child++;
if(array[pos]<array[child])
{
swap(&array[pos],&array[child]);
}
else
break;
}
}
void MaxHeapSort(int array[],int len)
{
int i;//len/2-1是最后一个非叶子节点
//循环执行后,变为了MaxHeap,array[0]为最大值
for(i=len/2-1;i>=0;--i)
{
AdjustMaxHeap(array,i,len);
}
//每次循环取出一个最大值,缩小heap的范围
for(i=len-1;i>=0;--i)
{
swap(&array[i],&array[0]);//保证array[i]为当前最大值
AdjustMaxHeap(array,0,i);//缩小heap范围
}
}
//位图排序
void SetBit(int n)
{
map[n>>5]=map[n>>5] | (1 <<(n&31));//n>>5是32求整,n&31是求32余数
}
int TestBit(int n)
{
return map[n>>5] & (1<<(n&31));//判断对应位是否为1
}
void BitMapSort(int array[],int len)
{
int i,k=0;
for(i=0;i<len;i++)
SetBit(array[i]);
for(i=1;i<=MAX;i++)
{
if(TestBit(i))
array[k++]=i;
}
}
void main()
{
int array[]={3,5,4,1,2,6};
//int array[]={6,5,4,3,2,1};
int len=sizeof(array)/sizeof(int);
//MaxHeapSort(array,len);
//BitMapSort(array,len);
//SelectSort(array,len);
//InsertSort(array,len);
//BubbleSort(array,len);
//MergeSort(array,0,len-1);
//QuickSort(array,0,len-1);
ShellSort(array,len);
for(int i=0;i<len;++i)
{
printf("%d ",array[i]);
}
}
二、性能比较
2.1 稳定性
插入(希尔除外)、冒泡、归并排序
2.2与数组初始顺序关系
选择排序和堆排序
因为:选择排序{有序}[无序],从无序里面选择出最小的数来,都得把[无序]里的元素全部比较一遍。
2.3时间复杂度
二大消耗空间的排序
归并排序,基数排序
一个时间和空间一样的排序
快速排序0(logn)
1、时间复杂度达到O(nlgn) 的排序算法有:快速排序、堆排序、归并排序。
2、上面前四大类排序中,不稳定的排序有:希尔排序、快速排序、堆排序、简单的选择排序。
稳定的排序有:插入排序(除希尔外)、冒泡排序、归并排序。
3、从平均时间性能而言,快速排序最佳,其所需要的时间最少,但快速排序在最坏的情况下,时间性能还不如堆排序和归并排序
。
所有简单排序和堆排序都是0(1) ,因为需要一个临时变量来交换元素位置,(另外遍历序列时自然少不了用一个变量来做索引)
快速排序为0(logn),要为递归程序执行过程 栈所需的辅助空间
归并排序空间复杂是O(n),需要一个大小为n的临时数组
桶排序的空间复杂度不确定