您的位置:首页 > 编程语言 > C#

使用C#详解常用排序算法(二):插入排序(Insert Sort)

2015-08-09 09:48 411 查看
把排序问题抽象下,其本质是给定一个输入,得出一个输出。其中输入和输出分别是:

输入(序列):n个数组成的一个序列 <a1,a2,...ai,...,an>

输出(序列):是输入序列的有序排列<a1',a2',...,ai',...,an'>,满足条件:a1'<=a2'<=...<=ai'<=...<=an'。

可以称呼序列中的任意一个数为序列中的元素,简称元素。

在排序过程中,一个序列中的元素必然处于下列三种情况中的一种:已经处在排好序的位置上;正在对次元素进行排序操作;待排。那么一个正在进行排序操作的序列必然有一定数目(可以是0)的元素是排列好的,一定数目的元素是未被排列好的。当序列中只有1个元素时,那么它必定可以认为是已排好序的。这点认识很重要。

插入排序(Insert Sort):本质上是待排序列里的元素一个一个的与已排列好的元素进行比较,将其插入到已排列好的序列中,直到没有待排列的元素。类似于打牌的时候摸牌的动作:手上的牌是排列好的,桌子上的牌是待排序的,每从桌子上抓到一只牌,按照一定次序将其插入到手中(如图):



下面上核心代码:

int i = 0, j = 0;
int key;
//for any j, means array from [0,...,j-1] is sorted.
//because the loops starts from j=1, so array[0] is one element
//and of course sorted.
for (j = 1; j < array.Length; j++)
{
// array[j] is the number to be inserted to sorted part
key = array[j];
// i starts from the left neighbor of j
i = j - 1;
//if array[i]>key then move array[i] to its right neightbor [i+1]
//and array[i] is just a copy of array[i+1] and is going to be
//replaced by key in proper position.
while (i >= 0 && array[i] > key)
{
array[i + 1] = array[i];
i -= 1;
//DisplayArrayToConsole(array);
}
array[i + 1] = key;
Console.Write("Step {0}:", j);
DisplayArrayToConsole(array);
}
我们结合实际运行情况来讲解插入排序算法,下图是程序的一个可能运行的截图:



首先:我们从控制台输入了一组数字,组成一个待排序序列:5,2,4,6,1,3 。在输入的时候请用合适的分隔符分开,这里的程序要求使用半角逗号 ","来分割。

循环从j=1开始,意味着我们首先要操作的数字”2“(请注意C#数组的下标从0开始),第一个数字5,我们认为它处在一个只有一个元素的序列中,也就可以认为是已经排好序的。首先要把这个数字2从数组里取出来,用它和已排好序的最末一个数(也是第1个数)5比较,发现2比5小,此时要做的一个事情是把数字5放到先前存储数字2的位置,如果这个时候观察一下数组的结构,应该是5,5,4,6,1,3。数字2已经不在数组里了,而是存储在key这个变量里。由于这个时候待排序列只有一个数字5,那么此时我们把数字2填到最左边的5这个位置,数组变成了:2,5,4,6,1,3。第1轮循环到此结束。

第2轮循环从j=2开始,这是排好序的是2,5;我们要把4从序列里取出来给key,用key先同(第2位的)5比较,发现5比4大,则将5的位置往后挪一位(也就是4的位置),随后将4同(第1位的)2比较,发现2比4小,那么原先5占据的第2位就让给待排的数字4。第二轮循环结束。

第3轮循环开始着手安排数字6的位置,当6同已排序列的最后一位5比较时,发现5比6小,那么此时就可以确定6的位置不需要变化。但是在程序里,其实做了这样一件事情,就是将数字6取出给key,比较了key与5之后,又把key交还给数字6所在的位置。

第4轮循环排序的是数字1,第五轮是最后一个待排数字3,同之前的描述差不多,不再赘述。

为了能够更直观的了解程序每一个关键交换步骤所做的操作,我们修改程序,显示更多数组在排序过程中的中间状态:在while的循环里添加输出数组到控制端的操作。我们更清楚的观察到while循环里每一步结束后数组的状态(下图)。正如前文所述,在第一个循环结束前数组中第1,2位都是数字5。这里也可以看到一开始将待牌元素赋值给变量key(key=array[j])是必须的操作,因为的排序过程中待排元素所在的位置是会被已排序列中的数字重写的,被重写的数字原先的位置其实是被释放了,只是程序并没有擦除(因为要再写一没有太大意义的代码)而已。读者可以自己尝试添加代码把释放的位置上做个标记(比如用数组序列中没有的数字代替)。



关于更多对插入算法的性能分析,可参考相关书籍。下节详解归并排序(Merge Sort)
本程序对应的main函数如下:
static void Main(string[] args)
{
int[] array;
array = Sorting.LoadArrayFromConsole();
Sorting.Insertion_Sort(array);
Console.ReadLine();
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息