插入排序
直接插入排序
将待排序列分为已排序序列和未排序序列,不断取出未排序序列中的元素放入已排序序列中合适的位置(指放之后已排序序列仍然有序)。下面的例子中,是一个待排的数组arr,先将0位置的元素认为是一个有序序列,1~len(arr)-1为无序,慢慢从1开始取元素加入有序部分,直到所有数组元素有序。
#include <iostream>
using namespace std;
void insert_sort(int arr[], int len)
{
int temp, i, j;
for(i = 1; i < len ; i++) //0位置单个元素默认有序,从1开始
{
temp = arr[i]; //temp保存每一轮想要排序的元素
j = i - 1; //j为已排序序列的末尾元素的位置
while(j>=0 && arr[j]>k) //在已排序序列内,查找k的大小位置
{
arr[j+1] = arr[j]; //将元素后移,为k腾出空位
j--; //在已排序序列内,由后向前循环
}
arr[j+1] = temp; //将需要排序的元素放到腾出的空位上
}
}
int main()
{
int arr[] = {7, 1, 4, 8, 3, 2};
int len = sizeof(arr)/sizeof(int);
for(int i = 0; i < len; i++)
{
cout << arr[i] << endl;
}
cout << "-------" << endl;
insert_sort(arr, len);
for(int i = 0; i < len; i++)
{
cout << arr[i] << endl;
}
return 0;
}
折半插入排序
在将一个新元素插入已排好序的数组的过程中,寻找插入点时,待插序列的首元素为arr[low],末元素为arr[high],比较时将待插入元素与arr[mid](mid=(low+high)/2)相比较,如果比参考元素大,则选择arr[low]到arr[m-1]为新的插入区域(即high=mid-1),否则选择arr[mid+1]到arr[high]为新的插入区域(即low=mid+1),如此直至low<=high不成立,即将此位置之后所有元素后移一位,并将新元素插入arr[high+1]。
#include <iostream>
using namespace std;
void binary_insert_sort(int arr[], int len)
{
int k, i, j;
int low, high, mid;
for(i = 1; i < len; i++)
{
low = 0;
high = i - 1;
k = arr[i]; //k用来保存待排序元素
while(low <= high) //利用折半查找,确定待排序元素在已排序序列中的位置
{
mid = (low + high) / 2;
if(arr[mid] < arr[i])
{
low = mid + 1;
}
else{
high = mid - 1;
}
}
for(j = i-1 ; j >= high+1 ; j--) //元素会插在arr[high+1]这个位置,而从high到i-1的元素会后移
{
arr[j+1] = arr[j];
}
arr[j+1] = k;
}
}
int main()
{
int arr[] = {7, 1, 4, 8, 3, 2};
int len = sizeof(arr)/sizeof(int);
for(int i = 0; i < len; i++)
{
cout << arr[i] << endl;
}
cout << "-------" << endl;
binary_insert_sort(arr, len);
for(int i = 0; i < len; i++)
{
cout << arr[i] << endl;
}
return 0;
}
希尔排序
又称为缩小增量排序。基本思路是将待排序列分割成若干个子序列,对每个子序列进行排序,然后缩小分割量(比如原本每隔4个元素为一组,现在变为2个),继续对缩小后的子序列排序,直到最后分割量为1。
#include <iostream>
using namespace std;
void shell_sort(int arr[], int len)
{
int gap; //步长
int i, j;
for(gap = len / 2; gap > 0; gap = gap / 2) //先取数组arr长度的一半,然后每次变为上次的1/2。
{
for(i = gap; i < len; i++) //这里需要注意
{
if( arr[i] < arr[i-gap]) //下面的内容基本与直接插入排序差不多,只是变成了间隔gap的元素排序。
{
int temp = arr[i];
j = i - gap;
while(j >= 0 && arr[j] > temp)
{
arr[j+gap] = arr[j];
j = j - gap;
}
arr[j+gap] = temp;
}
}
}
}
int main()
{
int arr[] = {7, 1, 4, 8, 3, 2};
int len = sizeof(arr)/sizeof(int);
for(int i = 0; i < len; i++)
{
cout << arr[i] << endl;
}
cout << "-------" << endl;
shell_sort(arr, len);
for(int i = 0; i < len; i++)
{
cout << arr[i] << endl;
}
return 0;
}
注意点:从上面shell_insert()函数中截取一段(也是注释里需要注意那块),如下。
for(i = gap; i < len; i++)
{
...
}
排序并不是将某个子序列完全排完,再下一个子序列。而是所有子序列轮着来orz