排序二:
给定N个(长整型范围内的)整数,要求输出从小到大排序后的结果。
输入:输入长度为N的一维整形数组arr。
输出:输出从小到大排序后的结果。
1、快速排序
时间复杂度:O(nlog2n)
稳定性:不稳定
优化目标:暂无
#include <stdio.h>
void QuickSort(int arr[],int left,int right){
if(left<right){
int i=left;
int j=right;
int key=arr[left]; //当前表的第一个元素设置为枢轴
while(i<j){ //找到枢轴的位置
while(i<j&&arr[j]>=key) --j;
arr[i]=arr[j]; //比枢轴小的元素移动到左端
while(i<j&&arr[i]<=key) ++i;
arr[j]=arr[i]; //比枢轴大的元素移动到右端
}
arr[i]=key;//枢轴元素放到最终位置
//依次对两个子表进行递归排序
QuickSort(arr,left,i-1); //对枢轴左边的元素进行排序
QuickSort(arr,i+1,right); //对枢轴右边的元素进行排序
}
}
int main(){
int N,arr[100]={0};
scanf("%d",&N);
for(int i=0;i<N;i++){
scanf("%d", &arr[i]);
}
int l=0,r=N-1;
QuickSort(arr,l,r);
for(int j=0; j<N; j++) {
printf("%d ",arr[j]);
}
}
2、堆排序
时间复杂度:O(nlog2n)
稳定性:不稳定
优化目标:暂无
#include <stdio.h>
void swap(int *x,int *y)
{
int temp;
temp=*x;
*x=*y;
*y=temp;
}
void HeadAdjust(int arr[],int index,int len){//调整以index为根的堆
int child=2*index+1; //child为根结点index的左孩子结点坐标
int key=arr[index]; //key暂存当前根结点值
while(child<len){
if(child+1<len&&arr[child]<arr[child+1]){//如果右孩子结点存在且值比左孩子结点大,child就加一,来记录较大结点的坐标
child++;
}
if(arr[child]>key){ //如果孩子结点的值比根结点的值大
arr[index]=arr[child]; //改变根结点的值
}
else{
break;
}
index=child;//向下,调整以孩子结点为根的堆
child=2*index+1;
}
arr[index]=key; //被筛选的结点放到最终位置
}
void HeapSort(int arr[],int len){
for(int i=len/2;i>0;i--){ //从i=n/2~1,反复调整结点,形成大根堆
HeadAdjust(arr,i,len);
}
for(i=len;i>1;i--){
swap(&arr[1],&arr[i]); //将堆顶和堆底元素进行交换(输出堆顶元素)
HeadAdjust(arr,1,i-1); //调整,将剩下i-1个元素整理成堆
}
}
int main(){
int N,arr[100]={0};
scanf("%d",&N);
for(int i=0;i<N;i++){
scanf("%d", &arr[i]);
}
HeapSort(arr,N);
for(int j=0; j<N; j++) {
printf("%d ",arr[j]);
}
}
3、归并排序
时间复杂度:O(nlog2n)
稳定性:稳定
优化目标:暂无
#include <stdio.h>
void merge(int arr[],int left,int right){
int i,j,k;
int mid=(left+right)/2;
int len=mid-left+1;
int *temp=malloc(sizeof(arr[0])*len); //构造辅助数组temp
for(i=0;i<len;i++){
temp[i]=arr[i+left]; //把数组arr中left~mid的元素复制到数组temp中
}
i=0,j=mid+1,k=left;
while(i<len&&j<=right){
if(temp[i]<arr[j]){ //把数组temp的元素和arr数组中mid+1~right这部分的元素进行比较,将较小的值存放到数组arr中
arr[k++]=temp[i++];
}else{
arr[k++]=arr[j++];
}
}
while(i<len){
//如果数组temp还没有遍历完,把temp后面的元素复制到arr中
arr[k++]=temp[i++];
}
free(temp);
}
void merge_sort(int arr[],int left,int right){
if(left<right){
int mid=(left+right)/2; //从中间划分两个子序列
merge_sort(arr,left,mid); //对[left,mid]这个区间的元素进行递归排序
merge_sort(arr,mid+1,right); //对[mid+1,right]这个区间内的元素进行递归排序
merge(arr,left,right); //归并
}
}
int main(){
int N,arr[100]={0};
scanf("%d",&N);
for(int i=0;i<N;i++){
scanf("%d", &arr[i]);
}
int l=0,r=N-1;
merge_sort(arr,l,r);
for(int j=0; j<N; j++) {
printf("%d ",arr[j]);
}
}
总结:今天继续复习了排序算法,快速排序、堆排序以及归并排序这三种排序算法相对于昨天复习的排序算法来说较为复杂,更加需要仔细理解,并且要能完整地模拟算法思路。其中快速排序是重点,它是所有内部排序算法中平均性能最优的排序算法,适合待排序关键字随机分布的情况。对于堆排序,它适合关键字较多的情况,另外大根堆形成的是递增序列,小根堆形成的是递减序列。排序算法的重要性毋庸置疑,应该及时回顾,加强记忆。