插入排序
void InsertSort(int* a, int n)
{
for(int i=0;i<n-1;i++)
{
int end=i;
int tmp=a[end+1];//后面一个
while(end>=0)
{
if(tmp<a[end])
{
a[end+1]=a[end];
end--;
}
else
{
break;
}
}
a[end+1]=tmp;//升序 当找到比tmp小的数a[end] 那么tmp排在它后面 tmp和a[end+1]交换
}
}
希尔排序
void ShellSort(int* a, int n)
{
int gap=n;
while(gap>1)
{
gap= gap / 3 + 1;//找到区间大小合适的gap值 第一次10/3+1=4 第二次4/3+1=2
//gap值套入插入排序
for(int i=0;i<n-gap;i++)
{
int end=i;
int tmp=a[end+gap];
while(end>=0)
{
if(tmp<a[end])
{
a[end+gap]=a[end];
end-=gap;
}
else
{
break;
}
}
a[end+gap]=tmp;
}
}
}
选择排序
void SelectSort(int* a, int n)//找最小 再交换
{
int min=0;
for(int i=0;i<n-1;i++)
{
min=i;
for(int j=i+1;j<n;j++)
{
if(a[min]>a[j])
min=j;
}
Swap(&a[i],&a[min]);
}
}
堆排序
void AdjustDown(int* a, int n, int parent)//调整
{
int child=parent*2+1;
while(child<n)
{
if(child+1<n&&a[child+1]>a[child]) child++;
if(a[child]>a[parent])
{
Swap(&a[child],&a[parent]);
parent=child;
child=parent*2+1;
}
else break;
}
}
void HeapSort(int* a, int n)
{
//建大堆
//从最下边的子树向下调整
for (int i = (n - 1 - 1) / 2; i >= 0; --i)
{
AdjustDown(a, n, i);
}
int end=n-1;
while (end>0)
{
Swap(&a[0],&a[end]);//把最大的数和末尾交换 再重新调整 保证以后每个最大的数都在顶点
AdjustDown(a,end,0);
end--;
}
}
冒泡排序
void BubbleSort(int* a, int n)//相邻两个比大小
{
for(int i=0;i<n;i++)
{
for(int j=1;j<n-i;j++)
{
if(a[j-1]>a[j])
{
Swap(&a[j-1],&a[j]);
}
}
}
}
快速排序——hoare版+挖坑法+快慢指针法——优化+三数取中
//三数取中
int GetMidIndex(int *a,int begin,int end)
{
int mid=(begin+end)/2;
if(a[begin]>a[mid])
{
if(a[mid]>a[end])
{
return mid; //begin> mid >end
}
else if (a[begin]>a[end])//begin > mid < end mid最小 再比较begin和end
return end; //begin> end >mid
else //谁小谁是中间值
return begin;//end> begin >mid
}
else //begin<mid
{
if(a[begin]>a[end])
{
return begin; //end< begin <mid
}
else if(a[mid]>a[end])//mid > begin < end begin最小 再比较mid和end
return end; //mid> end >begin
else
return mid; //begin< mid <end
}
}
// 快速排序递归实现 升序:右先找小 左再找大
void QuickSort(int* a,int begin,int end)
{
if(begin>=end) return;
if((end-begin+1)<15)//小区间优化 :当区间<15 直接使用插入排序代替 减少递归次数
{
InsertSort(a+begin,end-begin+1);
//1 2 3 4 5 | 4 6 4 3 1 区间在|后面 排的是|后的区间数组 所以a+begin
}
else
{
//int key=PartSort1(a, begin , end);//封装
//int key=PartSort2(a, begin , end);//封装
int key=PartSort3(a, begin , end);//封装
QuickSort(a,begin,key-1);//key-1是左区间的最大下标
QuickSort(a,key+1,end);//k+1是右区间最小下标
}
}
// 快速排序hoare版本
int PartSort1(int* a, int begin, int end)
{
int mid=GetMidIndex(a,begin,end);//三数取中
Swap(&a[begin],&a[mid]);//把中间数和第一个交换 让它变成key
int left=begin,right=end;
int key=left;
while (left<right) //key在左边先走右边
{
while (left<right&&a[right]>=a[key])//当不相遇时,右边找小于key的下标
{
right--;
}
while (left<right&&a[left]<=a[key])//不相遇时,左边找大于key的下标
{
left++;
}
Swap(&a[left],&a[right]);
}
Swap(&a[left],&a[key]);//key的值和最后left right相遇的值交换 key即归位
key=left;//左右被key分隔开
return key;
}
// 快速排序挖坑法
int PartSort2(int* a, int begin, int end)
{
int mid =GetMidIndex(a,begin,end);
Swap(&a[begin],&a[mid]);
int left=begin,right=end;
int key=a[left];//把第一个坑中的值保存起来
int hole=left;//坑位
while(left<right)
{
while(left<right&&a[right]<=key)//右找大
{
right--;
}
a[hole]=a[right];//坑位放值
hole=right; //新坑
while(left<right&&a[left]>=key)//左找小
{
left++;
}
a[hole]=a[left];
hole=left;
}
a[hole]=key;//把第一个坑中的值放到最后的坑里
return hole;//返回分割区间的key值
}
// 快速排序前后指针法
int PartSort3(int* a, int begin, int end)
{
int key=begin;
int prev=begin,cur=begin+1;
while(cur<=end)
{ //双指针法:cur一直往后走 遇到比key小的值 prev往后走1步 然后交换值
if(a[cur]<a[key] && ++prev!=cur) //后面的条件:交换也有代价(建立栈帧)
{
Swap(&a[prev],&a[cur]);
}
cur++;
}
Swap(&a[prev],&a[key]);
key=prev;//最后prev所在的位置则是分割区间的位置key
return key;
}
快速排序非递归法(用栈实现)
// 快速排序 非递归实现
void QuickSortNonR(int* a, int begin, int end)
{
Stack st;
StackInit(&st);
StackPush(&st,begin);//先入后出
StackPush(&st,end);//后入先出
while(!StackEmpty(&st))
{
int right=StackTop(&st);//取栈顶数据 end
StackPop(&st);//出栈
int left=StackTop(&st);//第二个就是 begin
StackPop(&st);
int key=PartSort1(a,left,right);//取分割区间的key
//分割成 left ~ key-1 key key+1 ~ right
//先入右边区间 再入左边区间
if(key+1<right)//如果区间只有一个值 就不用再排了
{
StackPush(&st,key+1);//先入右边区间的最左
StackPush(&st,right);//后入右边区间的最右 和初始化时一样
}
if(left<key-1)//如果区间只有一个值 就不用再排了
{
StackPush(&st,left);//先入左边区间的最左
StackPush(&st,key-1);//后入左边区间的最右
}
}
StackDestroy(&st);
}
快速排序——优化:三路划分
//快排 三路划分
void QuickSort(int* a,int begin,int end)//左闭右开
{
if(begin>=end) return;
if((end-begin+1)<15)//小区间优化 :当区间<15 直接使用插入排序代替 减少递归次数
{
InsertSort(a+begin,end-begin+1);
//1 2 3 4 5 | 4 6 4 3 1 区间在|后面 排的是|后的区间数组 所以a+begin
}
else
{
int mid=GetMidIndex(a,begin,end);
Swap(&a[begin],&a[mid]);
int left=begin,right=end;
int key=a[begin];
int cur=left+1;
while(cur<=right)
{
if(a[cur]<key)//把比key小的往前推
{
Swap(&a[cur],&a[left]);
cur++;
left++;
}
else if(a[cur]>key)//把比key大的往后推
{
Swap(&a[cur],&a[right]);
right--;
}
else //如果==key 就留在中间 区间为第一段和第三段
{
cur++;
}
}
QuickSort(a,begin,left-1);//key-1是左区间的最大下标
QuickSort(a,right+1,end);//right跑到前面去变成第二个区间的首位
}
}
归并排序
//归并排序
void MergeSort(int* a,int n)
{
int* tmp=(int*)malloc(sizeof(int)*n);//开一个空间去储存排好序的数组然后再复制到原数组中
if(tmp==NULL)
{
perror("Malloc error:");
exit(-1);
}
_MergeSort(a,0,n-1,tmp);
free(tmp);
tmp=NULL;
}
void _MergeSort(int* a, int begin, int end,int* tmp )
{
if(begin>=end)//结束条件
return;
int mid=(begin+end)/2;
int begin1=begin , end1=mid;//分区间
int begin2=mid+1 , end2=end;
_MergeSort(a , begin1 , end1 , tmp);//左区间排序
_MergeSort(a , begin2 , end2 , tmp);//右区间排序
int i=begin; //tmp的下标
while(begin1 <= end1 && begin2 <= end2)
{
if(a[begin1] < a[begin2])//两个区间排序
{
tmp[i++] = a[begin1++];//tmp的下标i一直往后走
}
else//升序
{
tmp[i++] = a[begin2++];
}
}
//当其中一个区间中的值还没被复制完
while(begin1 <= end1)
{
tmp[i++] = a[begin1++];
}
while(begin2 <= end2)
{
tmp[i++] = a[begin2++];
}
memcpy(a+begin,tmp+begin,sizeof(int)*(end-begin+1));//拷贝数组
// begin每次递归后的位置 闭区间 要+1 如 0~9应该是10个大小
}
归并排序-非递归
//归并非递归
void MergeSortNOR(int* a, int n)
{
int* tmp=(int*)malloc(sizeof(int)*n);//开一个空间去储存排好序的数组然后再复制到原数组中
if(tmp==NULL)
{
perror("Malloc error:");
exit(-1);
}
int rangeN=1;//归并的个数
while(rangeN<n)
{
for(int i=0;i<n;i+=rangeN*2)
{
int begin1=i,end1=i+rangeN-1;//闭区间
int begin2=i+rangeN,end2=i+rangeN*2-1;//end2=i + rangeN + rangeN-1第二个区间的位置比第一个区间大rangeN个
int j=i; //tmp的下标
//修正区间
if(end1>=n)//第一个区间尾部end1越界
{
end1=n-1;//数组末尾
//不存在的区间 使下面第二个区间的循环不会执行 防止越界
begin2=n;
end2=n-1;
}
else if(begin2>=n)//第二个区间的头部begin2越界 即这区间整体越界
{
//不存在的区间
begin2=n;
end2=n-1;
}
else if(end2>=n)//第二个区间尾部end2越界
{
end2=n-1;//数组末尾
}
while(begin1 <= end1 && begin2 <= end2)
{
if(a[begin1] < a[begin2])//两个区间排序
{
tmp[j++] = a[begin1++];//tmp的下标j一直往后走
}
else//升序
{
tmp[j++] = a[begin2++];
}
}
//当其中一个区间中的值还没被复制完
while(begin1 <= end1)
{
tmp[j++] = a[begin1++];
}
while(begin2 <= end2)
{
tmp[j++] = a[begin2++];
}
//memcpy(a,tmp,sizeof(int)*n);//修正区间后可以整体拷贝数组 也可以局部拷贝
}
memcpy(a,tmp,sizeof(int)*n);//修正区间后可以整体拷贝数组 也可以局部拷贝
rangeN*=2;//每次X2 扩大区间
}
free(tmp);
tmp=NULL;
}
计数排序
//计数排序
void CountSort(int* a, int n)
{
int max = a[0], min = a[0];
for (int i = 1; i < n; ++i)
{
if (a[i] < min)
min = a[i];
if (a[i] > max)
max = a[i];
}
int range = max - min + 1;
int* countA = (int*)calloc(range, sizeof(int));
if (countA == NULL)
{
perror ("calloc failln"); exit (-1);
}
for (int i=0;i<n;++i)
{
countA[a[i]-min]++;
}
int k = 0;
for (int j = 0; j <range; ++j)
{
while (countA[j]--)
{
a[k++] = j + min;
}
}
free (countA);
}