排序算法主要分为:插入排序,选择排序,交换排序,堆排序,基数排序等。本文想将这些排序写成一个系列,算法是按照自己的思路写的,没有把它作为教材的意图。水平一般,力图说的直白,易懂。
首先从插入排序写,第一篇是直接插入排序。
直接插入排序的思想简单说一下。将一个无序的数组a[n]看成两部分:有序表和无序表,通常是讲第一个元素a[0]作为有序表,a[1,..,n-1]是无序的。
排序开始:从i = 1,...n-1遍历,首先比较a[1] 与a[0]的大小(递增排列)a[1]>a[0],说明把a[1]从无序表中放入有序表中时,有序表内元素不需要移动,有序表变成{a[0],a[1]}。如果a[1] < a[0],说明有序表的元素应该是{a[1],a[0]},这就需要移动(大数往后移动,小数往前站),将a[1]存入临时变量,把a[0]放入a[1]的位置(a[0]往后撤一步),然后把临时变量里存的a[1]放到a[0]中,第一次遍历结束。红色表示元素是有序表中的元素,黑色表示是无序表的元素。
i 0 1 2 3 4 5
初始序列 21 25 3 *25 16 08
第一趟 21 25 3 *25 16 08
然后从无序表中拿出a[2],跟有序表中的元素比较,倒着比较,先跟a[1]比较,如果a[2]>a[1],说明有序表中的元素不需要移动,有序表变成{21,25,49},如果a[2]小于a[1],说明,a[2]应该放在a[1]的前边,将a[2]放入临时变量,a[1]后移一位,此时是否立即将a[2]放入a[1]空出来的位置里呢,这还要看a[2]和a[0]孰大孰小,如果a[2]>a[0],直接将a[2]放入a[1]的位置即可,a[0]后移。如果a[2]<a[0],则a[0]需要后移一位,然后将a[2]放入空位。
i 0 1 2 3 4 5
第二趟 3 21 25 *25 16 08
第三趟从无序表中拿出a[3](*25),首先跟a[2](25)比较,因为惯例上a[3]<a[2]的时候才会将a[2]后移,如果a[3]>=a[2],则无需移动,这既减少移动次数,还保证了数据的稳定性。
i 0 1 2 3 4 5
第三趟 3 21 25 *25 16 08
第四趟从无序表中取出a[4]和有序表中的数据倒序比较,小于a[3],a[2],a[1],所以吧a[4]存入临时变量,把a[3],a[2],a[1],以此后移一位,a[4]>a[0]因此a[0]无需移动,a[4]插入a[1]的位置即可。
i 0 1 2 3 4 5
第四趟 3 16 21 25 *25 08
同理,第五趟,拿无序表中的a[5]与有序表中的元素倒序比较,小于a[4],a[3],a[2].a[1],则将这四个元素依次后移,a[5](08)>a[0](3),a[0]不动,a[5]存入a[1]结束。
i 0 1 2 3 4 5
第五趟 3 16 21 25 *25 08
3 16 21 25 *25 08——>存入临时变量,a[4],a[3],a[2],a[1]依次后移
数组大小是6(n),排序趟数是5(n-1).外层循环i从1开始到n-1,内层循环j是从i-1到0,同时还要比较a[i]的值与它前面的有序表的值得大小。
在vs2008 下c++写的
1、新建类class Sort "Sort.h"
#pragma once
typedef struct node{
int key;
}DataType;
typedef struct {
DataType *elem;
int maxSize;
int num;
}DataList;
class Sort
{
public:
Sort(void);
~Sort(void);
void insertSort(DataList & L); //直接插入排序 想简单的话,参数直接写成 void(insertSort(int arr[], int n);
};
2、方法实现文件 ”Sort.cpp“
#include "StdAfx.h"
#include "Sort.h"
Sort::Sort(void)
{
}
Sort::~Sort(void)
{
}
void Sort::insertSort( DataList & L )
{
DataType temp;
int i = 0, j = 0;
for(i = 1; i < L.num; i++) // 第一层循环从i=1...n-1;
{
if (L.elem[i].key < L.elem[i-1].key) // 每次从无序表中拿出一个元素a[i]跟有序表的最后一个元素比较,如果大于有序表的最后一个 //<span style="font-family: Arial, Helvetica, sans-serif;">元素,则无需移</span><span style="font-family: Arial, Helvetica, sans-serif;">动,本次循环结束,a[i]成为有序表的最后一个元素。否则</span>
temp.key = L.elem[i].key; //将a[i]存入临时变量temp中。
for(j = i-1; j >= 0 && L.elem[j].key > temp.key; j-- ) //用a[i]即temp依次跟有序表[0,...,i-1]中的元素倒序比较。如果temp小于有序
{
L.elem[j+1] = L.elem[j]; //表中的元素,则将有序表中的元素后移一位。知道temp遇到比他小的元素,
}
L.elem[j+1] = temp; //无需移动,将temp放入空位即可。
}
}
}
如果原始列表是有序的,这是最好情况,只需n-1次比较即可O(n)。移动次数为0。
如果原始列表是逆序的。则是最坏情况,需要n(n-1)/2次比较O(n^2)。移动次数约(n^2)/2(即O(n^2))。
平均的时间复杂度是O(n^2)。
是稳定的排序方法。
辅助空间O(1)。