SortFunc.h
//
// SortFunc.hpp
// FirstP
//
// Created by 赫赫 on 2023/11/1.
// 排序算法代码
#ifndef SortFunc_hpp
#define SortFunc_hpp
#define MaxSize 100
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
using namespace std;
#endif /* SortFunc_hpp */
//待排序数组A,数组元素个数n
//一、插入排序
//直接插入排序(带哨兵)
void InsertSort(int A[],int n);
//折半插入排序(带哨兵)
void HalfInsertSort(int A[],int n);
//希尔排序
void ShellSort(int A[],int n);
//二、交换排序
//交换功能
void swap(int &a,int &b);
//冒泡排序
void BubbleSort(int A[],int n);
//快排(重点!!!)
//用第一个元素将待排序序列划分为左右两个部分,每一次划分确定一个元素位置
int Partition(int A[],int low,int high);
//快排函数体
void QuickSort(int A[],int low,int high);
//三、选择排序
//简单选择排序
void SelectSort(int A[],int n);
//堆排序(重点!!!)
//以k为根的子树调整为大根堆
void HeadAdjust(int A[],int k,int len);
//建立大根堆
void BuildMaxHeap(int A[],int len);
//堆排序函数体(调用上面的两个函数)
void HeapSort(int A[],int len);
//四、归并排序
int *B=(int *)malloc(MaxSize*sizeof(int));
//二路归并排序
void Merge(int A[],int low,int mid,int high);
void MergeSort(int A[],int low,int high);
SortFunc.cpp
//
// SortFunc.cpp
// FirstP
//
// Created by 赫赫 on 2023/11/1.
//
#include "SortFunc.hpp"
//直接插入排序(带哨兵)
//从前往后,从小到大排序
void InsertSort(int A[],int n){
int i,j;
//i从2开始时因为一个元素已经有序
for(int i=2;i<=n;i++){//前i-1个是已经有序的序列
if(A[i]<A[i-1]){//第i个元素与第i-1个元素比较
//如果小于,则需要插入前面的有序序列,如果大于,则证明i与前面的i-1个元素有序
A[0]=A[i];
for(j=i-1;A[0]<A[j];j--){//插入前i-1个元素的比较过程
A[j+1]=A[j];
}
A[j+1]=A[0];
}
}
}
//折半插入排序(带哨兵)
//在对前面有序序列中使用折半查找的方式去确定插入位置
void HalfInsertSort(int A[],int n){
int i,j,low,high,mid;
//i从2开始时因为一个元素已经有序
for(int i=2;i<=n;i++){//前i-1个是已经有序的序列
A[0]=A[i];
low=1;
high=i-1;
while(low<=high){
mid=(low+high)/2;
if(A[0]<A[mid]){
high=mid-1;
}else{
low=mid+1;
}
}
//当low>high时停止折半查找操作,将high+1及以后的元素往后移
for(j=i-1;j>=high+1;j--){
A[j+1]=A[j];
}
A[high+1]=A[0];
}
}
//希尔排序
//对每次分割开的特殊子表进行直接插入操作
void ShellSort(int A[],int n){
int d,i=0,j=0;
//此处数据依然是从1开始的,不过下标为0处并不是哨兵,而是暂存单元
//d为步长
for(d=n/2;d>=i;d=d/2){//步长变化,每次除以2
for(i=d+1;i<=n;i++){
if(A[i]<A[i-d]){//特殊子表的前面部分已经有序,第i个与有序的最高位比较,如果小于则向前找插入位置
A[0]=A[i];
for(j=i-d;j>0&&A[0]<A[j];j-=d){//找插入位置过程
A[j+d]=A[j];//记录右移
}
A[j+d]=A[0];//插入
}
}
}
}
//二、交换排序
void swap(int &a,int &b){
int temp=a;
a=b;
b=temp;
}
//冒泡排序
void BubbleSort(int A[],int n){
for(int i=0;i<n-1;i++){
bool flag=false;//标记检测一趟是否产生了交换
for(int j=n-1;j>i;j--){
if(A[j]<A[j-1]){
swap(A[j], A[j-1]);
flag=true;
}
}
if(flag==false){
//如果没有则说明列表已经有序,可以提前跳出for循环,排序完成
return;
}
}
}
//快排
//用第一个元素将待排序序列划分为左右两个部分,每一次划分确定一个元素位置
int Partition(int A[],int low,int high){
int pivot=A[low]; //取第一个元素作中枢结点
while(low<high){
while(A[high]>=pivot){ //右侧元素大于中枢元素,不移动
high--;
}
A[low]=A[high]; //将右侧小于中枢的元素移到左侧
while(A[low]<=pivot){ //左侧元素小于中枢元素,不移动
low++;
}
A[high]=A[low]; //将左侧大于中枢的元素移到右侧
}
A[low]=pivot; //将中枢元素放到确定位置
return low; //返回确定的中枢元素位置
}
//快排函数体
void QuickSort(int A[],int low,int high){
if(low<high){//跳出递归的条件
int pivotpos=Partition(A, low, high);//划分
QuickSort(A, low, pivotpos-1); //划分左子表
QuickSort(A, pivotpos+1, high); //划分右子表
}
}
//三、选择排序
//简单选择排序
void SelectSort(int A[],int n){
for(int i=0;i<n-1;i++){
int min=i;//记录最小元素的位置
for(int j=i+1;j<n;j++){//找后面未排好序元素中的最小元素并记录位置
if(A[min]>A[j]){
min=j;
}
}
if(min!=i){//将最小元素放到前面
swap(A[min],A[i]);
}
}
}
//堆排序(重点!!!)
//调整为大根堆(以k位置元素为根的子树)
void HeadAdjust(int A[],int k,int len){
A[0]=A[k];//A[0]暂存子树的根节点
for(int i=2*k;i<=len;i*=2){//这个就是小元素下坠的过程
if(i<len&&A[i]<A[i+1]){//取key较大的子结点作为和根结点的比较对象
i++;
}
if(A[0]>=A[i]){
break;
}else{
A[k]=A[i];
k=i; //记录修改的位置i,在下一次for循环用i作为根节点和子树去比较
}
}
A[k]=A[0];
}
//建立大根堆
void BuildMaxHeap(int A[],int len){
for(int i=len/2;i>0;i--){//从后往前调整所有非终端结点
HeadAdjust(A, i, len);
}
}
//堆排序函数体(调用上面的两个函数)
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); //把剩余的待排序元素整理成堆
}
}
//四、归并排序
//空间复杂度主要来自辅助数组B,空间复杂度O(n)
//时间复杂度O(nlog(n)),归并趟数log(n)趟
//二路归并排序Merge操作,时间复杂度O(n)
void Merge(int A[],int low,int mid,int high){
int i,j,k;
//将A待排序数组放入B中
for(k=low;k<high;k++){
B[k]=A[k];
}
//i,j分别表示B中两个子列表的遍历指针,k指A数组中待放入元素的位置
for(i=low,j=mid+1,k=i;i<=mid&&j<=high;k++){
if(B[i]<=B[j]){
A[k]=B[i]; //将较小的值复制到A中
i++;
}else{
A[k]=B[j];
j++;
}
}
//最后把剩余已经有序的子列表数据直接放到A的最后即可
while(i<=mid){
A[k++]=B[i++];
}
while(j<=high){
A[k++]=B[j++];
}
}
//二路归并排序函数体:递归调用
//先通过子列表只有一个元素的两两组合,然后子元素扩展到两个、四个...直到全部
void MergeSort(int A[],int low,int high){
if(low<high){
int mid=(low+high)/2; //从中间划分
MergeSort(A, low, mid); //对左半部分归并排序
MergeSort(A, mid+1, high); //对右半部分归并排序
Merge(A,low,mid,high); //对两个有序的子序列归并
}
}