排序算法详解

1. 直接插入排序(有序表的扩大)

void InsertSort(int *A,int n){
    int i,j;
    for(i=2;i<=n;i++){   //从第二个元素开始遍历n-1次,插入到前面的有序数组中
        A[0]=A[i];      //存储待插入元素
        for(j=i-1;A[0]<A[j];--j)  
            A[j+1]=A[j];    //将大于待插入元素的元素往后移动一位,空出插入位置
        A[j+1]=A[0];        //插入元素
    }
}
折半插入排序
void InsertSort(int *A,int n){
    int i,j,low,high,mid;
    for(i=2;i<=n;i++){   //从第二个元素开始遍历n-1次,插入到前面的有序数组中
        A[0]=A[i];      //存储待插入元素
        low=1;high=i-1;//有序数组的左右两端指针
        while(low<=high){ //折半查找出待插入位置
            mid=(low+high)/2;
            if(A[mid]>A[0]) high=mid-1;
            else low=mid+1;
        }
        for(j=i-1;j>=high+1;--j)  //跳出条件直接使用了插入位置high
            A[j+1]=A[j];    //将大于待插入元素的元素往后移动一位,空出插入位置
        A[j+1]=A[0];        //插入元素
    }
}
希尔排序
void InsertSort(int *A,int n){
    int i,j;
    for(dk=n/2;dk>=1;dk=dk/2)    //步长每次缩小一半直至变为1
        for(i=dk+1;i<=n;i++){   //从第1+dk个元素开始遍历,插入到前面的有序非连续数组中
            if(A[i]<A[i-dk]){  //有序则跳过该次循环
                A[0]=A[i];      //存储待插入元素
                for(j=i-dk;j>0&&A[0]<A[j];j-=dk)  //变换的步长为dk
                    A[j+dk]=A[j];    //将大于待插入元素的元素往后移动dk位,空出插入位置
                A[j+dk]=A[0];        //插入元素
            }
        }
}

2. 冒泡排序(逐个冒出最值)

void BubbleSort(int *A,int n){
    for(int i=0;i<n-1;i++){  //遍历n-1趟
        flag = false;       //设置标志位,当数组有序即一趟没发生交换时,跳出循环
        for(int j=n-1;j>i;j--){ //从后往前交换
            if(A[j-1]>A[j]){    //冒出最小值
                swap(A[j-1],A[j]);
                flag=true;
            }
        }
        if(flag==flase) return;
    }
}

3. 快速排序(枢轴递归分治)

void QuickSort(int *A,int low,int high){
    if(low>=high) return;
    int pivot_pos=Partition(A,low,high); //使枢轴右侧大于左侧并返回枢轴位置
    QuickSort(A,low,pivot_pos-1);   //递归枢轴左半边
    QuickSort(A,pivot_pos+1,high);  //递归枢轴右半边
}

int Partition(int *A,int low,int high){
    int pivot= A[low];      //默认第一个元素为枢轴元素,并存储起来
    while(low<high){
        while(low<high&&A[high]>=pivot) --high//移动右端指针至小于枢轴的元素
        A[low]=A[high];  //将该元素换至左端
        while(low<high&&A[low]<=pivot) ++low;//移动左端指针至大于枢轴的元素
        A[high]=A[low]; //将该元素换至左端
    }
    A[low]=pivot;//枢轴元素放回枢轴位置
    return low;//返回枢轴位置
}

4. 简单选择排序(选出最值)

void SelectSort(int *A,int n){
    for(int i=0;i<n-1;i++){     //从前往后,进行n-1趟遍历
        min = i;                //记录这趟遍历最小值位置
        for(j=i+1;j<n;j++)      //选出该趟遍历最小元素
            if(A[j]<A[min]) min=j; //选出最小值
        if(min!=i) swap(A[i],A[min]); //如果最小元素不是待插入位置,则交换
    }
}

5. 堆排序(利用堆的性质不断调整和冒出最值)

void HeapSort(int *A,int len){
    BuildMaxHeap(A,len);    //建立大根堆
    for(int i=len;i>1;i--){  //n-1趟交换和建堆过程
        swap(A[i],A[1]);     //输出堆顶元素(和堆底元素交换)
        HeadAdjust(A,1,i-1); //把剩余i-1个元素调整成堆
    }
}

void BuildMaxHeap(int *A,int len){
    for(int i=len/2;i>0;i--)        //从i=~n/2~1,反复调整堆
        HeadAdjust(A,i,len);       //调整算法把左右子树皆为堆的树调整成堆
}

void HeadAdjust(int *A,int k,int len){
//将元素k为根的子树进行调整
    A[0]=A[k];      //A[0]暂存子树根节点
    for(int i=2*k;i<=len;i*=2){      //该循环是为了将根节点值不断往下送
        if(i<len&&A[i]<A[i+1])     i++;  //若右节点大,指针移动到右节点
        if(A[0]>A[i]) break;  //调整结束,即根节点大于两子节点
        else{               //否则继续将根节点的值往下送
            A[k]=A[i];      //根节点位置换成较大子节点的值
            k=i;            //记录子节点指针作为新的根节点或终止节点
        }
    }
    A[k]=A[0]; //循环结束终止节点赋往下送根节点值
}
    

6. 归并排序(分治归并有序子表)

void MergeSort(int *A,int low,int high){
    if(low>=high) return;
    int mid = (low+high)/2; //数组分成两部分
    MergeSort(A,low,mid);   //对左边递归排序使其有序
    MergeSort(A,mid+1,high); //对右边递归排序使其有序
    Merge(A,low,mid,high);   //合并两有序表
}
void Merge(int *A,int low,int mid,int high){
    for(int k=low;k<=high;k++){
        B[k]=A[k];      //复制出一个新的数组作为比较
    for(int i=low,j=mid+1,k=i;i<=mid&&j<=high;k++){ //从左往右,两个指针对两数组逐个对比
        if(B[i]<B[j]) A[k]=B[i++];  //将小的值赋回给A,并移动指针
        else A[k]=B[j++];
    }

    while(i<=mid) A[k++]=B[i++]; //将没复制完的复制过去
    while(j<=high) A[k++]=B[j++]; //将没复制完的复制过去
    }
}
posted @ 2022-05-11 21:09  失控D大白兔  阅读(53)  评论(0编辑  收藏  举报