直接插入排序:
思想:
将要排序的序列看成两个序列,一个是有序序列,另一个是无序序列,每次取无序序列中的元素往有序序列中的合适位置插入,直到无序序列为空,排序完成。
图解示例(红色为有序序列黑色为无序序列)
执行步骤:
(1)一个数可以认为是有序的,所以第一次区间划分如上图;
(2)在无序序列中取一个数,从有序序列的最后一个数开始向前扫描,若该元素大于前一个元素则插入该位置;
(3)重复执行(2);
(4)待无序序列为空时排序完成。
代码实现:
#include<iostream>
#include<assert.h>
using namespace std;
template<class T>
void Print(const T* a, size_t n)
{
for (size_t i = 0; i < n; ++i)
{
cout << a[i] << " ";
}
cout << endl;
}
template<class T>
struct Less //升序
{
bool operator()(const T& l, const T& r)
{
return l < r;
}
};
template <class T>
struct Great //降序
{
bool operator()(const T& l, const T& r)
{
return l > r;
}
};
template<class T,class Compare>
void InsertSort(T* a, size_t n) //插入排序
{
assert(a);
for (size_t i = 1; i < n; ++i)
{
int end = i - 1; //end用来保存有序区间的最后一个数据的位置
T temp = a[i]; //temp用来保存无序区间的第一个数据,也是即将要插入有序区间的数据
while (end >= 0)
{
if (Compare()(temp, a[end])) //利用仿函数实现比较
{
a[end + 1] = a[end]; //为temp[i]留出合适的位置
end--;
}
else
break;
}
a[end+1] = temp; //将temp插入到合适的位置
}
}
void TestInsertSort()
{
int a[] = { 3, 5, 7, 2, 4, 1, 9, 8, 6 };
InsertSort<int, Less<int>>(a, sizeof(a) / sizeof(a[0]));//升序
Print(a, sizeof(a) / sizeof(a[0]));
InsertSort<int, Great<int>>(a, sizeof(a) / sizeof(a[0]));//降序
Print(a, sizeof(a) / sizeof(a[0]));
}
template<class T,class Compare>
void ShellSort(T* a,size_t n)
{
assert(a);
int gap = n;
while (gap > 1)
{
gap = gap / 3 + 1; //+1是为了最后一次对全体数据进行插入排序
for (size_t i = gap; i < n; i++)
{
int end = i - gap;
T tmp = a[i];
while (end >= 0)
{
if (Compare()(tmp, a[end]))
{
a[end + gap] = a[end];
end = end - gap;
}
else
break;
}
a[end + gap] = tmp;
}
}
}
void TestShellSort()
{
int a[] = { 2, 5, 4, 9, 3, 6, 8, 7, 1, 0 };
ShellSort<int, Less<int>>(a, sizeof(a) / sizeof(a[0]));
Print(a, sizeof(a) / sizeof(a[0]));
ShellSort<int, Great<int>>(a, sizeof(a) / sizeof(a[0]));
Print(a, sizeof(a) / sizeof(a[0]));
}
template<class T,class Compare>
void SelectSort(T* a, size_t n)
{
assert(a);
for (size_t i = 1; i < n; ++i)
{
int minIndex = i; //未排序区间的最小数据下标
int start = i - 1; //未排序区间的第一个数据下标
//选出第二部分最小数据
for (size_t j = i + 1; j < n - 1; ++j) //用i+1来不断的缩小j的范围
{
if (Compare()(a[j + 1], a[minIndex]))
swap(a[j + 1], a[minIndex]);
else
break;
}
//第二部分最小数据和第三部第一个数据进行比较
if (Compare()(a[minIndex], a[start]))
swap(a[minIndex], a[start]);
}
}
void TestSelectSort()
{
int a[] = { 2, 5, 4, 9, 3, 6, 8, 7, 1, 0 };
SelectSort<int, Less<int>>(a, sizeof(a) / sizeof(a[0]));
Print(a, sizeof(a) / sizeof(a[0]));
SelectSort<int, Great<int>>(a, sizeof(a) / sizeof(a[0]));
Print(a, sizeof(a) / sizeof(a[0]));
}
运行结果:
复杂度与稳定性分析:
最坏时间复杂度:O(n^2)序列处于逆序或基本逆序的情况下
最好时间复杂度:O(n)序列有序或基本有序的情况下
空间复杂度:O(1)
稳定性:稳定