**一次性实现所有排序的思想**
冒泡排序、插入排序、选择排序、快速排序、
希尔排序,归并排序、计数排序、基数排序、
桶排序、堆排序
升序排序******
一次全部解决,代码中的注释非常清楚,主函数中释放对应排序方式的 // 就执行对应排序,所有被调函数都不释放就是原本的顺序,使用的软件是VS2019。
放几张图片先。
//冒泡排序、快排、插入排序、选择排序、希尔排序、归并排序、堆排序、基数排序、桶排序、计数排序
//以下排序均为升序排序
//时间复杂度的对比
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 10 //数组中数字个数,暂定10
#define M 50 //数组最大范围的定义
#define GREAT 10000 //Great 代表N个数字当中的最大值比Great小
int main();
int bubbling(int*);//冒泡排序 o(n^n)
int insert(int*);//插入排序 o(n^n)
int select(int*);//选择排序 o(n^n)
int fast(int*,int ,int);//快排 o(nlog^n)
int shell(int*); //希尔排序 o(nlog^2n)
int merge_sort(int* ,int, int); //归并排序 o(nlog^n)
int base(int*); //基数排序 o(n)
int bucket(int*); //桶排序(计数排序) o(n)
int heap(int*, int,int); void build_sortheapify(int *); //堆排序 o(nlog^n)
int main()
{ //数组中元素数值大小不得大于10000
int arrary[] = { 134,54,342,99,88,45,200,87,99,165 };//数字数组大小必须与N一致
int newarrary[M];
int i;
printf("原数组为:\t ");
for (i = 0; i < 10; i++)
printf("%4d", arrary[i]);
printf("\n\n");
//***************函数调用区******************************
//bubbling(arrary);
//insert(arrary);
//select(arrary);
//fast(arrary, 0, N-1);
//shell(arrary);
//merge_sort(arrary,0,N);
//base(arrary);
//bucket(arrary);
//build_sortheapify(arrary);
//*******************************************************
for (i = 0; i < N; i++)
newarrary[i] = arrary[i];
printf("指定方式排序之后为: ");
for (i = 0; i < N; i++)
{
printf("%4d", newarrary[i]);
}
return 0;
}
int bubbling(int* arrary)//冒泡排序
{
int i, j, change = 0;
for(i=1;i<N;i++) //i从第二个元素开始进行n-1次循环
//i也可以从0开始循环,但是后面的查找就要变为j-1和j,j从i开始
for (j = 0; j < N-i; j++)//遍历循环
//第一次排序外层i为1,内层循环9次依次比较相邻两个元素的大小,依次将较大者放在最后
//最后放在了j+1==8+1==9,即是数组最后一个元素,当走完这次内层循环之后
//最后一个元素已经是当前最大,那么,下一次排序将不再考虑他,
//如何实现呢?这就是外层循环(从1开始自加的作用,因为j+1的原因),
//下一次开始10就-2了,最后一个元素放在第八个位置,依次类推,
//直到i=9;10-i==1,内层就不会再循环,跳出for()for(),排序成功!
{
if (arrary[j] > arrary[j + 1])//如果不满足要求的较小的值在前面,就执行以下操作实现change
{
change = arrary[j]; arrary[j] = arrary[j + 1]; arrary[j + 1] = change;
}
//先把较大的arrary[j]的值暂时放在change中,将较小的arrary[j+1]赋值给arrary[j]
//再把change中存放的较大的值赋值给arrary[j+1]
}
return arrary[M];
}
int insert(int* arrary)//插入排序
//思路如下:从第二个元素开始,将他和前一个对比,排序,然后,后面2和3、3和4
//比如第三个开始插入排序,若是比第二个大,就不懂,若是小,往前挪动一个位置,然乎前一个后移一个位置
//循环条件是i>0,知道插入的元素比前一个大,就结束本轮插入
{
int i, j;
int temp;//临时放置数据的变量
for(i=1;i<N;i++)
if (arrary[i] < arrary[i - 1])
//这里注意,if是用来做判断的,while是用来做循环的
//if不会回过头来执行当前if结构体,while会回过头来执行当前结构体,直到条件不成立
{
temp = arrary[i]; //temp就是要插入的元素值
j = i; //记录当前最后一个元素的位置
while (j > 0 &&temp<arrary[j-1])
{
arrary[j] = arrary[j - 1];
j--;
}
arrary[j] = temp; //在插入循环停下来的位置,把temp的值给当前位置的数组
}
return arrary[M];
}
int select(int* arrary)//选择排序
{
int i, j;
int min,temp;
//思路是将当前最小元素放在最后,然后和当前第一个元素交换
for (i = 0; i < N - 1; i++)
{
min = i; //从第一个元素至倒数第二个元素,每次记录当前位置为min找到当前min后change
for (j = i + 1; j < N; j++) //从i的下一个元素开始
{
if (arrary[min] > arrary[j]) min = j; //又发现比min小的,就重置min的数据与位置
//发现有比min还小的就把他的位置给min,方便后面找最小元素
//此循环的目的发现比min所在位置小的元素就让当前位置位置元素是min所在位置元素
//依次找出当前最小元素
}
if (i != min)
{
temp = arrary[i];
arrary[i] = arrary[min];
arrary[min] = temp;
} //如果i比之后的元素都小,就不执行交换,因为他就是当前最小元素
//该过程是将拍好的当前min所在位置的最小元素放在当前i所在位置,i从左往右走
}
return arrary[M];
}
int fast(int* arrary, int begin, int end)//快速排序
//思路就是将第一个元素放置在他该放的位置,左边全是比他小的元素,右边全是比他大的元素,然后用递推放置其他元素
{
if (begin > end)
return 0;
int t;
int temp = arrary[begin]; //将基数begin暂时存在temp中
int i = begin;
int j = end;
while (j > i)
{
while (arrary[j] >= temp) //这里是必须等于,不然数组中出现相同元素时候就会出错
j--;
if (arrary[j] < temp&&i<j)
{
t = arrary[j];
arrary[j] = arrary[i];
arrary[i] = t;
}
while (arrary[i] <= temp&&i<j) //这里是必须等于,不然数组中出现相同元素时候就会出错
i++;
if (arrary[i] > temp)
{
t = arrary[i];
arrary[i] = arrary[j];
arrary[j] = t;
}
}
fast(arrary, begin, i-1); //递归排序左半边
fast(arrary, i+1, end); //递归排序右半边
}
int shell(int* arrary)//希尔排序
{ //随着分组越来越细,数组越来越趋近于正确排序
int i,j,temp,k,gap; //定义分组最大间隔gap
for (gap = 3; gap > 0; gap--) //每组分组间隔逐渐缩小
{
for (i = 0; i < gap; i++) //这里遍历第一个点和第一个间隔点之间的元素,之后+gap就是每组对应元素
{
for (j = i + gap; j < N; j += gap) //这个for当中的每个j对应元素为一组
{
if (arrary[j] < arrary[j - gap]) //对每组元素进行插入排序
{
temp = arrary[j]; //temp就是要插入的元素
k = j - gap; //k是每组中j前一个元素
while (k > 0 && arrary[k] > temp)
{
arrary[k + gap] = arrary[k]; //arrary[k]较大的话,将其在组中后移一个单位
k=k-gap; //继续在该组中前移比较能否插入
}//结束时候停下来,不满足了,不会继续循环,但是k已经-了gap,就该+上gap才是该插入的位置
arrary[k + gap] = temp; //将temp插入当前轮次属于他的位置
}
}
}
} //第170到179行代码实则就是插入排序
return arrary[M];
}
int merge_sort(int* arrary, int start, int end)//归并排序
{ //传进来的end是字符串长度
if (end == start+1) //当只有两个元素,再次二分之后退出递推
{
return 0;
}
int mid = start+(end - start) / 2;
merge_sort(arrary, start, mid);
merge_sort(arrary, mid , end); //每一次都二分
int i = start;
int j = mid;
int k = 0;
int temp[N]; //以下为合并
for (; i < mid && j < end;)
{
if (arrary[i] < arrary[j])
{
temp[k++] = arrary[i++];
} //找到下的就先放然后挪动位置,然后两个二分区域各自位置比较,小的放到temp,
//直到二分中的一个归置完
else
{
temp[k++] = arrary[j++];
}
} //然后将未排完的半区直接放在temp剩余位置,都满了,就不执行后面的两个while
//在每个分区拍好后合并,所以每次的分区其实都是排好了顺序的
if (i < mid) //做判断
{ //说明右边赋值完毕,左边有剩余
while (i < mid) //做循环
{
temp[k++] = arrary[i++];
}
}
if (j < end) //做判断
{ //说明左边边赋值完毕,右边边有剩余
while (j < end) //做循环
{
temp[k++] = arrary[j++];
}
}
//两个while最多只会执行一个
for (i = 0; i < end-start; i++)
{
arrary[i+start] = temp[i];
}
}
int base(int* arrary)//基数排序
{ //思想是从个位开始,按照个位大小排序,然后十位---直到当前最大位
//数组长度是N,最大数字是max,max的位数是bit
int i, max = 0,base=1;
for (i = 0; i < N; i++)
{
if (arrary[i] > max)
max = arrary[i];
} //找到了最大数max
int* t = (int*)malloc(sizeof(int) * N);
while (max / base > 0)
{
int bucket[N] = { 0 };
for (i = 0; i < N; i++)
{ //计算每个桶里面数字的个数
bucket[arrary[i] / base % 10]++; //依次从个位开始得到每一位的数字,每次之后桶往后挪动
//对应位的数字是多少就放在几号桶,找到当前位数对应桶,当前桶++;最后得到当前桶数字个数
}
for (i = 1; i < N; i++)
{
bucket[i] += bucket[i - 1]; //累加,计算i个桶及其之前桶内数字个数的总和
}
for (i = N - 1; i >= 0; i--)
{ //这里用开辟了空间的t[]来存放
int position = arrary[i] / base % 10; //position是几号桶
t[bucket[position] - 1] = arrary[i]; //bucket[position]就是他的当前位数数字大小排在第几位,
bucket[position]--;
} //对应数组下标就是bucket[position]-1
for (i = 0; i < N; i++)
{
arrary[i] = t[i];
}
base *= 10;
}
return arrary[M];
}
int bucket(int* arrary)//桶排序
{
int i, k;
int b[GREAT]; //b的下标就是arrary元素大小,所以数组大小可以尽量大
memset(b, 0, sizeof(b)); //使用b数组之前清空他
for (i = 0; i < N; i++)
{
k = arrary[i]; //依次把数组元素给k
b[k]++; //然后arrary数组元素的大小就是b的下标,++的作用是记录当前下标数组元素个数
} //也就是相同的数字的个数,至少有一个,后面方便判断;
//实际上,就把数值转换为了下表,就已经排好了序
int j = 0;
for (i = 0; i < GREAT; i++)
while (b[i] > 0) //后面有b[i]--会while循环b[i]次重复输出相同的数字
{
arrary[j++] = i; //返回给arrary
b[i]--;
}
return arrary[M];
}
int heap(int* arrary,int n, int i)//堆排序,n是当前数组元素个数
{ //就是建立子树节点
//父节点是(i-1)/2
if (i >= n)
{
return 0;
}
int c1 = 2 * i + 1;
int c2 = 2 * i + 2;
//这两个是子节点
int max = i;
if (c1<n && arrary[c1]>arrary[max])
{
max = c1;
}
if (c2<n && arrary[c2]>arrary[max])
{
max = c2;
}
if (max != i)
{
int t;
t = arrary[max];
arrary[max] = arrary[i];
arrary[i] = t;
heap(arrary,n, max);
}
}
void build_sortheapify(int *arrary)
{
int last = N-1;
int parent = (last - 1) / 2; //last,parent都是指的下标
int j;
for (j = parent; j >= 0; j--)
{
heap(arrary,N, j);
} //至此构建好了子树结点
int k;
for (k = N - 1; k >= 0; k--)
{
int m;
m = arrary[k];
arrary[k] = arrary[0];
arrary[0] = m;
heap(arrary, k, 0);
//每次将最后一个结点和arrary[0]change,应为arrary[0]heap之后就是当前最大值
//然后砍掉最后一个元素,所以数组要变短所以数组长度要是k
}
}