一.直接插入排序(Direct insertion sort)概述
在为排序序列中,构建一个子排序序列,直至全部数据排序完成
将代排序的数,插入到已经排序的序列中合适的位置
增加一个哨兵,放入比较值,让它和后面已经排好的序列比较,找到合适的插入点
二.直接插入排序原理
初始值:[1 9 8 5 6]
第一趟:[0 1 9 8 5 6] [9 1 9 8 5 6] -> [1 9 8 5 6]
#如大家所看到的,和初始值必须,我在第一个位置上增加了一个数字0,这个数字0的位置我们称其为哨兵,接下来我们直接取初始值的第二个索引9和它前面一个索引比较(第一个索引相比较),哨兵9比1大,则不需要交换位置,本轮比较结束。
第二趟:[8 1 9 8 5 6] [8 1 ? 9 5 6] [8 1 8 9 5 6] -> [1 8 9 5 6]
#拿到上一轮比赛结果,接下来我们直接取初始值的第三个索引8和它前面一个索引比较,本轮哨兵为8,而哨兵8比9小,因此,我们需要把9往右移动一位,此时哨兵被插入8和9交换位置索引变为第二个索引,此时依旧需要和前面的一个索引进行比较,很显然第一个索引为1,而哨兵为8,哨兵8比1大,则不需要交换位置,本轮比赛结束。(简单的说就是如果比本轮哨兵大就相互交换位置,如果比本轮哨兵小则本轮结束)
第三趟:[5 1 8 9 5 6] [5 1 8 ? 9 6] [5 1 ? 8 9 6] [5 1 5 8 9 6] -> [1 5 8 9 6]
#拿到上一轮比赛结果,接下来我们直接去初始值的第四个索引5和它前面一个索引比较,本轮哨兵为5,而哨兵5比9小,因此他们需要相互交换位置,接着哨兵5再和它前面一个索引比较,哨兵5比8小,继续交换位置,然后继续和它前面一个索引比价,发现哨兵5比1大,终止本轮比赛。
第四趟:[6 1 5 8 9 6] [6 1 5 8 ? 9] [6 1 5 ? 8 9] [6 1 5 6 8 9] -> [1 5 6 8 9]
#拿到上一轮的结果,继续重复插入排序比较,经过上面3次比较,想必大家也清楚它是如何排序的了,最终经过四趟比较,得到的排序是:1 5 6 8 9
思路:后面去前面想比较,一次比较,一次换位置,比较一次,换一次位置。
插入排序与选择排序的比较与实现:
SortTestHelper.h:
#ifndef INC_04_INSERTION_SORT_SORTTESTHELPER_H
#define INC_04_INSERTION_SORT_SORTTESTHELPER_H
#include <iostream>
#include <algorithm>
#include <string>
#include <ctime>
#include <cassert>
using namespace std;
namespace SortTestHelper {
int *generateRandomArray(int n, int range_l, int range_r) {
int *arr = new int[n];
srand(time(NULL));
for (int i = 0; i < n; i++)
arr[i] = rand() % (range_r - range_l + 1) + range_l;
return arr;
}
int *generateNearlyOrderedArray(int n, int swapTimes){
int *arr = new int[n];
for(int i = 0 ; i < n ; i ++ )
arr[i] = i;
srand(time(NULL));
for( int i = 0 ; i < swapTimes ; i ++ ){
int posx = rand()%n;
int posy = rand()%n;
swap( arr[posx] , arr[posy] );
}
return arr;
}
int *copyIntArray(int a[], int n){
int *arr = new int[n];
copy(a, a+n, arr);
return arr;
}
template<typename T>
void printArray(T arr[], int n) {
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
cout << endl;
return;
}
template<typename T>
bool isSorted(T arr[], int n) {
for (int i = 0; i < n - 1; i++)
if (arr[i] > arr[i + 1])
return false;
return true;
}
template<typename T>
void testSort(const string &sortName, void (*sort)(T[], int), T arr[], int n) {
clock_t startTime = clock();
sort(arr, n);
clock_t endTime = clock();
cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << " s"<<endl;
assert(isSorted(arr, n));
return;
}
};
#endif //INC_04_INSERTION_SORT_SORTTESTHELPER_H
SelectionSort.h(选择排序):
#ifndef INC_04_INSERTION_SORT_SELECTIONSORT_H
#define INC_04_INSERTION_SORT_SELECTIONSORT_H
#include <iostream>
#include <algorithm>
using namespace std;
template<typename T>
void selectionSort(T arr[], int n){
for(int i = 0 ; i < n ; i ++){
int minIndex = i;
for( int j = i + 1 ; j < n ; j ++ )
if( arr[j] < arr[minIndex] )
minIndex = j;
swap( arr[i] , arr[minIndex] );
}
}
#endif //INC_04_INSERTION_SORT_SELECTIONSORT_H
main.cpp:
#include <iostream>
#include <algorithm>
#include "SortTestHelper.h"
#include "SelectionSort.h"
using namespace std;
template<typename T>
//插入排序
void insertionSort(T arr[], int n){
for( int i = 1 ; i < n ; i ++ ) {
// 寻找元素arr[i]合适的插入位置
// 写法1
// for( int j = i ; j > 0 ; j-- )
// if( arr[j] < arr[j-1] )
// swap( arr[j] , arr[j-1] );
// else
// break;
// 写法2
for( int j = i ; j > 0 && arr[j] < arr[j-1] ; j -- )
swap( arr[j] , arr[j-1] );
}
return;
}
int main() {
int n = 10000;
cout<<"Test for Random Array, size = "<<n<<", random range [0, "<<n<<"]"<<endl;
int *arr1 = SortTestHelper::generateRandomArray(n,0,n);
int *arr2 = SortTestHelper::copyIntArray(arr1, n);
SortTestHelper::testSort("Insertion Sort", insertionSort,arr1,n);
SortTestHelper::testSort("Selection Sort", selectionSort,arr2,n);
delete[] arr1;
delete[] arr2;
cout<<endl;
return 0;
}
结果的比较:
利用赋值语句改进插入排序算法(其他不变改进主函数的插入排序算法):
改进后的main.cpp
#include <iostream>
#include <algorithm>
#include "SortTestHelper.h"
#include "SelectionSort.h"
using namespace std;
template<typename T>
//插入排序
void insertionSort(T arr[], int n){
//改进的排序算法
for( int i = 1 ; i < n ; i ++ ) {
T e = arr[i];
int j;//j用来保存元素e应该插入的位置
//利用赋值语句来取代交换语句
for(j=i;j>0&&arr[j-1]>e;j--){
arr[j] = arr[j-1];
}
arr[j]=e;
}
}
int main() {
int n = 10000;
cout<<"Test for Random Array, size = "<<n<<", random range [0, "<<n<<"]"<<endl;
int *arr1 = SortTestHelper::generateRandomArray(n,0,n);
int *arr2 = SortTestHelper::copyIntArray(arr1, n);
SortTestHelper::testSort("Insertion Sort", insertionSort,arr1,n);
SortTestHelper::testSort("Selection Sort", selectionSort,arr2,n);
delete[] arr1;
delete[] arr2;
cout<<endl;
return 0;
}
改进后的结果: