折半插入排序
折半插入排序最难理解的地方在于:插入点位置
那么如何确定插入点的位置呢?
- 首先贴出查找的过程
while(left<=right) {
int mid = (left + right)/2;
if(p[mid] > p[0]) {
right = mid - 1;
} else {
left = mid + 1;
}
}
- 可以看出跳出while循环的前一步一定是:left = right = mid
- 此时只有两种情况
1)如果 p[mid] > 关键字 则执行 right = mid - 1
此时位置情况:__ right mid(left) __
所以插入的位置:right后面一个,即left
2)如果p[mid] < 关键字 则执行:left = mid + 1
此时位置情况:__ mid(right) left __
所以插入的位置:right后面一个,即left
- 综上所述,插入的位置一定是left(right+1)
#include<bits/stdc++.h>
using namespace std;
#define maxn 100
void print_p(int p[],int n) {
for(int i=1;i<=n;i++) {
cout<<p[i]<<" ";
}
cout<<endl;
}
//折半插入排序
void insert_mid_sort(int p[],int n)
{
///数据从1开始存储
for(int i=2;i<=n;i++) {
p[0] = p[i]; ///哨兵 暂存当前值
int left = 1;
int right = i-1;
while(left<=right) {
int mid = (left + right)/2;
if(p[mid] > p[0]) {
right = mid - 1;
} else {
left = mid + 1;
}
}
/**
if left == right == mid
(1) p[mid] > p[0]
==> right = mid - 1
此时位置情况:__ right mid(left) __
所以插入的位置:right后面一个,即将mid(left)
(2) p[mid] < p[0]
==> left = mid + 1
此时位置情况:__ mid(right) left __
所以插入的位置:right后面一个,即将left
**/
for(int j=i-1;j>=left;j--) { ///将left开始都向后移动一个位置
p[j+1] = p[j];
}
p[left] = p[0];
}
print_p(p,n);
}
///希尔排序
void shell_sort(int p[],int n) {
for(int gap = n/2; gap>=1; gap/=2) { ///增量gap
for(int i=gap+1; i<=n; i++) {
if(p[i] < p[i-gap]) { ///如果当前的值比前面的小,不然没必要去插入
int j;
p[0] = p[i];
for(j = i-gap; j>0&&p[j]>p[0]; j-=gap) { ///在同组内进行插入排序
p[j+gap] = p[j];
}
p[j+gap] = p[0];
}
}
}
print_p(p,n);
}
int main() {
int p[] = {0,1,5,2,4,3,7,6,8};
int n = 8;
//insert_mid_sort(p,n);
shell_sort(p,n);
}