本来打算昨天发,结果竟然学了一个晚上,自认为大学数据结构学得还不错,重新翻一遍竟然看了这么久还没有理解透彻,更加坚定了我一天一算法的决心。昨天和今天的排序一块写出来一块总结道插入排序里好啦。
老样子,代码走起。
<pre name="code" class="csharp">using System;
/// <summary>
/// 插入排序
/// </summary>
namespace test
{
class MainClass
{
public static void Main (string[] args)
{
int [] arr = {3, 1, 33, 4, 6, 2, 8, 14, 5};
//DirectInsertSort (arr);
//BinaryInsertSort (arr);
ShellSort (arr);
foreach (int i in arr) {
Console.WriteLine (i);
}
}
//直接插入排序,最简单的排序,从数组第二个数开始作为关键字向前面的数字组成的数组
//一次对比,并将自己插入前面数组第一个比他大的数前面,前面数组后面的数依次后移一位
private static void DirectInsertSort (int [] arr) {
int temp = 0; //存放作为关键字的元素的值
int j = 0;
for (int i = 1; i < arr.Length; i++) { //从数组第二个数开始遍历
temp = arr [i];
for (j = i - 1; j >= 0 && arr [j] > temp; j--) { //如果碰到一个比temp大的数,则temp索引位前比temp大的数
arr [j + 1] = arr [j]; //的索引位大的数依次后移一位
}
arr [j + 1] = temp; //由于for循环最后执行一次j--,所以将temp给j+1位的元素
}
}
//折半插入排序,由于插入排序是对有序数列插入,前面已经排好的序列通过折半查找找到插入元素的位置
private static void BinaryInsertSort (int [] arr) {
for (int i = 1; i < arr.Length; i++) {
int temp = arr [i]; //中间变量,存放对比的关键值
int low = 0;
int high = i - 1;
while (low <= high) {
int middle = (low + high) / 2;
if (temp < arr [middle]) { //若中间值大于temp说明temp的位置应该在middle后面,反之亦然
high = middle - 1;
} else {
low = middle + 1;
}
}
for (int j = i; j > high + 1; j--) {
arr [j] = arr [j - 1];
}
arr [high + 1] = temp;
}
}
//希尔排序,增量的规则一般是第一次取长度一半,第二次取一半的一半,一次递推,希尔排序不稳定
//增量也可以根据实际情况写一个函数,增量是用来分割数组的,每组数字都具有增量的函数特性
//好的增量序列的共同特征:
//1.最后一个增量必须为1
//2.应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况
private static void ShellSort (int [] arr) {
int i, j, increment; //increment表示增量
int temp = 0;
increment = arr.Length / 2;
//根据increment分割的各组进行直接插入排序
while (increment > 0) {
for (i = increment; i < arr.Length; i++) {
temp = arr [i];
for (j = i - increment; j >= 0 && arr [j] > temp; j -= increment) {
arr [j + increment] = arr [j];
}
arr [j + increment] = temp;
}
increment = increment / 2; //每次循环increment取半,直到为1
}
}
}
}
插入排序的根本思想在于每次对有序数列进行插入值,所以前两种排序都是稳定的,时间复杂度皆为n2,而希尔排序由于多次分成多个部分进行插入排序,是不稳定的,复杂度根据增量而定,好的增量会使希尔排序的效率很高。