一、快速排序
(1)基本思想
- 在待排序的n个元素中任取一个元素(通常取第一个元素)作为基准,把该元素放入最终位置后,整个数据序列被基准值分割成两个子序列,所有小于基准值的元素放置在前子序列中,所有大于基准值的元素放置在后子序列中,并把基准值排在这两个子序列的中间,这个过程称作划分。
- 然后对两个子序列分别重复上述过程,直至每个子序列内只有一个记录或空为止。
- 关键在于划分
(2)算法
int Partition(int r[],int s,int t) //划分算法
{ int i=s,j=t;
int tmp=r[s]; //用序列的第1个记录作为基准
while (i!=j) //从序列两端交替向中间扫描,直至i=j为止
{ while (j>i && r[j]>=tmp)
j--; //从右向左扫描,找第1个关键字小于tmp的r[j]
r[i]=r[j]; //将r[j]前移到r[i]的位置
while (i<j && r[i]<=tmp)
i++; //从左向右扫描,找第1个关键字大于tmp的r[i]
r[j]=r[i]; //将r[i]后移到r[j]的位置
}
r[i]=tmp;
return i;
}
void QuickSort(int r[],int s,int t)
//对r[s..t]元素序列进行递增排序
{ if (s<t) //序列内至少存在2个元素的情况
{ int i=Partition(r,s,t);
QuickSort(r,s,i-1); //对左子序列递归排序
QuickSort(r,i+1,t); //对右子序列递归排序
}
}
(3)时间复杂度与空间复杂度的分析
1.时间复杂度
2.空间复杂度分析
平均时间复杂度:O(nlog2n)
平均空间复杂度:O(log2n)
二、归并排序
(1)基本思想
关键在于合并算法,把俩个有序数组合并成一个新的有序数组
自顶向下的二路归并排序算法
例如,对于{2,5,1,7,10,6,9,4,3,8}序列,说明其自顶向下的二路归并排序的过程。
(2)算法
void MergeSort(int r[],int s,int t)
//二路归并算法
{ int mid;
if (s<t) //子序列有两个或以上元素
{ mid=(s+t)/2; //取中间位置
MergeSort(r,s,mid); //对a[s..mid]子序列排序
MergeSort(r,mid+1,t); //对a[mid+1..t]子序列排序
Merge(r,s,mid,t); //将两子序列合并,见前面的算法
}
}
void Merge(int r[],int s,int mid,int t)
//r[s..mid]和r[mid+1..t]→r[s..t]
{
int *tmpa;
int i=s,j=mid+1,k=0;//k用来记录temp数组的长度
tmpa=(int *)malloc((t-s+1)*sizeof(int));
while (i<=mid && j<=t)
if (r[i]<=r[j]) //将第1子表中的元素放入tmpa中
{
tmpa[k]=r[i];
i++;
k++;
}
else //将第2子表中的元素放入tmpa中
{
tmpa[k]=r[j];
j++;
k++;
}
while (i<=mid) //将第1子表余下部分复制到tmpa
{
tmpa[k]=r[i];
i++;
k++;
}
while (j<=t) //将第2子表余下部分复制到tmpa
{
tmpa[k]=r[j];
j++;
k++;
}
for (k=0,i=s;i<=t;k++,i++) //将tmpa复制回数组r中
r[i]=tmpa[k];
free(tmpa); //释放tmpa所占内存空间
}
(3)时间复杂度的分析与空间复杂度的分析
(4)自底向上的二路归并排序算法
基本思想:
void MergePass(int r[],int length,int n)
//一趟二路归并排序
{ int i;
for (i=0;i+2*length-1<n;i=i+2*length) //归并length长的两相邻子表
Merge(a,i,i+length-1,i+2*length-1);
if (i+length-1<n) //余下两个子表,后者长度小于length
Merge(a,i,i+length-1,n-1); //归并这两个子表
}
void MergeSort(int r[],int n) //二路归并算法
{ int length;
for (length=1;length<n;length=2*length)
MergePass(r,length,n);
}