选择排序\插入排序\希尔排序
- 选择排序
首先找到数据序列中最小(最大)的那个元素,其次将它和数组的第一个元素交换位置,然后在剩下的元素中找到最小的元素,将它和序列中第二个元素交换位置,循环执行,直至到达序列的最后一个元素位置.之所以叫做选择排序,是因为在每一轮排序中都在选择最小(最大)的那个元素.
选择排序的运行时间和输入无关,当前的一轮排序并不能为下一轮排序提供排序信息,这也导致当输入序列是一个有序序列的时候,选择排序依然会老老实实的经历Length轮排序.在选择排序过程中,数据移动的次数为Length次,每一轮排序选出一个,然后交换.
typedef struct {
int r[max];
int length;
}Sort_Alg;
void Select_Alg(Sort_Alg *L){
int min;
for (int i = 0; i < L->length; ++i) {
min=i;
for (int j = i+1; j < L->length; ++j) {
if(L->r[j]<L->r[min]){
min=j;
}
}
if(min!=i){
exchangeIndex(L,min,i);
}
}
}
- 插入排序
是将一个数据插入到一个已经排好序的序列中,在未知序列元素的情况下,只能将数组的第一个元素作为已经排好序的有序序列
从序列的第二个数据开始,将其与第一个数据进行比较,如果比第一个大,就放着不管,比第一个小就将第一个数据往后移一步,将第二个插入到第一个数据中去.
然后读取序列的第三个说,首先将其与第二个数据比较,如果比第二个大,就放着不管,比第二个小,就将第二个数据往后移一步,将第三个放在第二个索引位置,然后再与第一个数据进行比较,如果比第一个大,就放着不管,结束插入,如果比第一个小,就将第一个数据往后移一步,此时第三个数据就位于第一个索引位置.如此往复即可.
需要明确的是,插入排序中当前插入数据的左侧序列始终是有序的,执行第N轮排序时,数据间比较的最大次数是N-1次比较和N-1次数据交换.
void Insert_Alg(Sort_Alg *L){
for (int i = 1; i < L->length; ++i) {
for (int j = i; j > 0; --j) {
if(L->r[j]<L->r[j-1]){
exchangeIndex(L,j,j-1);
}
}
}
}
- 希尔排序
高级版插入排序
整个排序的过程是使序列中的元素保持H间隔有序,比如:
序列[1,4,7,2,6,9,3,7,12]
间隔H=2有序,分别是
[1,2,3]
[4,6,7]
[7,9,12].
从序列输入开始,使用Length/2(或者Length/3)作为间隔,对元素进行排序,一轮排序过后,将间隔再次除2(或除3),直至到间隔为1.
希尔排序的高效性是体现在,排序前对序列进行了分组,对每一组子序列进行排序后,子序列均表现为部分有序,满足插入排序的需求.
希尔排序的性能取决于间隔H与每个H之间的关系,(…有点儿深奥,我靠死记硬背的,间隔H-两层循环-内外递减-完事儿…)
void ShellSort_Alg(Sort_Alg *L){
int N=L->length;
int h=1;
while(h<N/2){
h=2*h;
}
while (h>=1){
for (int i = h; i < N; ++i) {
for (int j = i; j >= h; j-=h) {
if(L->r[j]<L->r[j-h]){
exchangeIndex(L,j,j-h);
}
}
}
h/=2;
}
}
- 归并排序
归并排序的流程更像是将排序的工作分成两部分,然后再将该两部分再次分别分为两部分,直至触底,这里的触底指的是分到了只有一个元素的时候,肯定是一个有序序列,所以就触底了,然后再返回这个分半的上级分半.高级的说法叫做"分治".
这里进行分治之后,就需要进行归并的操作了,例如已知两序列有序序列A和B,要将这两个序列归并成一个有序序列,即分别从两序列头索引开始,先进行比较,如果A序列的A[0]小于B序列的B[0],此时将A[0]放入大序列,A的索引自增1,B索引不变,然后将A[1]与B[0]进行比较,直至A和B两个序列抵达尾索引即完成归并.
总得来说一共两步:
拆拆拆…并并并…
void MergeSort_Alg(Sort_Alg *L,int left,int right){
if(right-left<1)
return;
int mid=(left+right)/2;
MergeSort_Alg(L,left,mid);
MergeSort_Alg(L,mid+1,right);
Merge_Alg(L,left,right);
}
void Merge_Alg(Sort_Alg *L,int left,int right){
int i=left,j=(left+right)/2+1,k=left,mid=(left+right)/2;
int temp[L->length];
for (int l = left; l <= right; ++l) {
temp[l]=L->r[l];
}
while(k<=right){
if (i>mid){
L->r[k]=temp[j];
k++;j++;
} else if (j>right){
L->r[k]=temp[i];
k++;i++;
} else {
if (temp[i] < temp[j]) {
L->r[k] = temp[i];
k++;i++;
} else {
L->r[k] = temp[j];
k++;j++;
}
}
}
}