算法之直接插入排序:
解析:手工过程是算法实现的重要一步,在没有搞清楚手工过程之前,坚决不允许进行代码的编写。
例如数据:4 7 8 1 0 9 2 53 6
对应下标为:0 1 2 3 4 5 6 78 9
对如上数据进行直接插入排序,将如上数据问分为两组,如:
(4)7 8 1 0 9 25 3 6,
此时,(4)为第一组,后边的为第二组,将第二组的每一个元素插入到第一组中的“合适”位置(根据升序或者降序排列)。以此类推,将第二组的数据全部插入到第
组,就完成了整个排序的过程。
排序过程:
(4)7 8 1 0 9 25 3 6
(4 7)8 1 0 9 2 53 6
(4 7 8)1 0 9 2 5 36
…….
(0 1 2 4 5 78 9)3 6
(0 1 2 3 4 5 78 9)6
(0 1 2 3 4 5 67 8 9)
从待排序的序列中取出第一个数据,与已排序序列的数据进行比较,找到其“合适”的位置,将合适位置的其后的所有元素依次向后移动一个元素空间,完成“插入”。
假设当前要处理的带排序序列的第一个元素下标为i
num = data[i]; //要插入的元素num
for(index = 0; index < count &&data[i] < num; index++)
;
即:data[i] = data[i-1]; data[i-1] = data[i-2];……data[index+1] = data[index]此时得到的index就是 “合适”的位置,接下来将合适的位置及以后的元素依次向后移动一个元素空间。
然后给下标为index的位置,插入元素num
代码:
for(int j = i; j > index; j--) {
data[j] = data[j-1];
}
//执行插入:
data[index] = num;
如上方式,依次将待排序序列中的每一个元素进行插入操作,这就是整个直接插入排序的过程。
完整代码如下:
C语言:
#include<stdio.h>
#include<malloc.h>
#include<time.h>
#include<stdlib.h>
typedef unsigned char boolean;
#define TRUE 1
#define FALSE 0
void directInsertSort(int *array, int count);
void initData(int *array, int count, int minValue, int maxValue);
void showArray(int *array, int count);
void showArray(int *array, int count) {
int i;
for(i = 0; i < count; i++) {
printf(i == 0 ? "%d" : ", %d", array[i]);
}
printf("\n");
}
void initData(int *array, int count, int minValue, int maxValue) {
int i = 0;
int value = maxValue - minValue + 1;
srand(time(0));
for(i = 0; i < count; i++) {
array[i] = minValue + rand()%value;
}
}
//直接插入排序,升序
void directInsertSort(int *array, int count) {
int i;
int index; //用来标记合适的插入位置
int j;
int temp; //这是要进行插入的值
for(i = 0; i < count; i++) {
temp = array[i];
//先找出插入合适的插入位置
for(index = 0; index < i && array[index] < temp; index++);
//将找到的合适位置放入要插入的值
for(j = i; j > index; j--) {
array[j] = array[j-1];
}
array[index] = temp;
}
}
void main(void) {
int *array;
array = (int *)calloc(sizeof(int), 20);
initData(array, 20, 1, 100);
showArray(array, 20);
directInsertSort(array, 20);
showArray(array, 20);
}
Java语言:
public class Main {
public static void main(String[] args) {
int[] array = new int[20];
int maxValue = 100;
initData(array, maxValue);
showData(array);
directInsertSort(array);
showData(array);
}
private static void showData(int[] array) {
for(int i = 0; i < array.length; i++) {
System.out.printf(i == 0 ? "%d" : ", %d", array[i]);
}
System.out.println();
}
private static int[] initData(int[] array, int maxValue) {
for(int i = 0; i < array.length; i++) {
array[i] = (int)(Math.random()*maxValue);
}
return array;
}
private static void directInsertSort(int[] array) {
int len = array.length;
int temp;
for(int i = 0; i < len; i++) {
temp = array[i];
int index;
for(index = 0; index < i && array[index] < temp; index++);
for(int j = i; j > index; j--) {
array[j] = array[j-1];
}
array[index] = temp;
}
}
}
对直接插入排序的讨论:
1、时间复杂度空间复杂度:
时间复杂度主要由:比较和移动两步组成,且每一步操作比较和排序次数和都是一个固定的值i(i代表已排序的数的个数)
外层循环总共需要进行n-1次,因此,时间复杂度为:
空间复杂度:1+2+3+.....+i+....+n-1 => O(n(n-1)/2)
O(1)
2、稳定和非稳定排序:
直接插入排序算法为稳定排序
稳定排序:在任意一排序过程中,如果出现几个元素的值相同,这几个相同元素的相对位置在排序前和排序后的位置不发生变化,即,为稳定排序;
非稳定排序:反之。
3、极端情况下的时间复杂度讨论:
在完全顺序、完全逆序的情况下,比较和移动此处之和相同
完全顺序,比较次数最多,移动次数最少;
完全逆序,比较次数最少,移动次数最多。