1. 直接插入排序
思想:其基本思路就是将一个数插入一个已经有序的数据结构中。这里的数组从1下标开始存数据,代码如下:
void InsertSort(int *arr,int len)
{
int i,j;
for(i=2;i<=len;++i)
{
if(arr[i]<arr[i-1])
{
arr[0]=arr[i]; //设置哨兵
for(j=i-1;arr[j]>arr[0];j--)
{
arr[j+1]=arr[j]; //数据后移,循环结束,即找到了起始的要插入的数该插入的实际位置
}
arr[j+1]=arr[0]; //将要插入的哨兵位数据插入对应位置
}
}
}
直接插入排序的时间复杂度为O(n2),即二次方。
2. 堆排序
堆分为大顶堆和小顶堆,每个结点的值都大于或等于其左右孩子结点的值,就称为大顶堆,或者每个结点的值均小于或等于其左右孩子结点的值,称为小顶堆。
解决堆排序存在两个问题:(1)如何由一个无序序列构建一个堆;(2)如何利用一个大顶堆做升序排序,代码如下:
void HeapSort(int *arr,int len)
{
int i;
for(i=len/2;i>0;i--)
{
HeapAdjust(arr,i,len); //调整所有非叶子结点所在子树为大顶堆
}
for(i=len;i>1;i--)
{
swap(arr,1,i); //大顶堆的首个元素就是所有数中的最大值,所以每次只需要将arr[1]与最后一个元素交换,此后该位置的值不再变化
HeaoAdjust(arr,1,i-1); //交换之后,对剩下的1~i-1的下标数据调整为大顶堆
}
}
void HeapAdjust(char *arr,int sindex,int mindex)
{
int tmp,j;
tmp=arr[sindex]; //tmp保存当前根结点数值
for(j=2*sindex;j<=mindex;j*=2) //j为i的左孩子结点
{
if(j<m&& arr[j]<arr[j+1]) //如果左孩子下标在合理范围内并且左孩子数值小于右孩子数值
{
++j; //此时j记录的是左右孩子中数值较大的下标
}
if(tmp>=arr[j]) //如果根结点的值比左右孩子中最大的值都大,则不需要做任何改变,跳出循环
{
break;
}
else
{
arr[sindex]=arr[j]; //如果根结点的值小于左右孩子中最大的值,则将左右孩子中最大的值赋值给根结点,
sindex=j; //根结点下标变为原先左右孩子中较大值的下标
}
}
arr[sindex]=tmp; //将新的根结点赋值成原来的根结点数值
}
堆排序的时间复杂度为O(nlog(n))。
3. 归并排序
思想:假设初始序列含有n个数值记录,则可以看成n个有序子序列,每个子序列长度为1,然后两两归并,直到得到一个完整的有序序列。代码如下:
void MergeSort(int *arr,int len)
{
Msort(arr,arr,1,len);
}
void Msort(int sr[],int tr1[],int s,int t) //将sr[s.....t]归并排序为tr1[s....t]
{
int mid;
int tr2[MAXSIZE+1]; //用来临时存放归并后的有序记录
if(s==t)
{
th1[s]=sr[s];
}
else
{
mid=(s+t)/2;
Msort(sr,tr2,s,m); //将sr[s...m]归并为有序tr2[s....m]
Msort(sr,tr2,m+1,t); //将sr[m+1...t]归并为有序tr2[m+1....t]
Merge(tr2,tr1,s,m,t); //将tr2[s...m]和tr2[m+1.....t]合并为有序tr1[s....t]
}
}
void Merge(int sr[],int tr[],int i,int m,int n)
{
for(j=m+1,k=1;i<=m&&j<=n;k++) // i为左半部分最左边下标,j为右半部分最左端下标,k表示最终合并排好序的tr数组的下标
{
if(sr[i]<sr[j]) //如果整个最左端小,就将小的放入tr数组中
{
tr[k]=sr[i++];
}
else
{
tr[k]=sr[j++]; //否则,将sr[j]放入tr中,再让j后移
}
}
if(i<=m) //循环结束后,若是前半部分未放完,而后半部已完,则将前半部分剩余数据以此拷贝至tr数组中
{
for(int x=0;x<=m-i;x++)
{
tr[k+x]=sr[i+x];
}
}
if(j<=n) //循环结束后,若是后半部分未放完,而前半部已完,则将后半部分剩余数据以此拷贝至tr数组中
{
for( x=0;x<=n-j;x++)
{
tr[k+x]=sr[j+x];
}
}
}
归并排序时间复杂度为O(nlog(n)).
4. 非递归的归并排序算法
void MergeSort2(int arr[],int len)
{
int *tr=(int *)malloc(sizeof(int)*len);
int k=1;
while(k<len)
{
MergePass(arr,tr,k,len);
k=2*k;
MergePass(tr,arr,k,len);
k=2*k;
}
}
void MergePass(int sr[],int tr[],int s,int n)
{
int i=1;
int j;
while(i<=n-2*s+1)
{
Merge(sr,tr,i,i+s-1,i+2*s-1);
i=i+2*s;
}
if(i<n-s+1)
{
Merge(sr,tr,i,i+s-1,n);
}
else
{
for(j=i;j<=n;j++)
{
tr[j]=sr[j];
}
}
}