目录
算法概述
1、十种常见排序算法可以分为两大类:
非线性时间比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此称为非线性时间比较类排序。
线性时间非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此称为线性时间非比较类排序。
2、算法复杂度
3、相关概念
稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。
时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。
空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。
插入排序
1、思想:逐个比较。将data[i]逐个与data[j](0<j<i),从而将data[i]放在data[]中合适的位置
2、复杂度:O(n^2)
3、缺点:存在多次多余且重复的移动,使效率低。
4、源代码:
#include <iostream>
using namespace std;
template<class T>
void insertionsort(T data[],int n)
{
for (int i = 1,j;i < n;++i) {//注意,这里不能用i<=n,因为data[n]超出了索引范围
//int data[7]为data内有7点int,但data[7]已经超出范围,从零开始计算
T tem = data[i];
for (j = i;j > 0 && tem < data[j-1];--j) {
data[j] = data[j - 1];
}
data[j] = tem;
}
}
template<class T>
void printdata(T data[], int n)
{
for (int i = 0;i < n;++i) {//注意,这里不能用i<=n
cout << data[i] << " ";
}
}
int main() {
double data[] = { 10, 165, 12.5, 16, 5.5, 132, 1 ,651 };
insertionsort(data, 8);
printdata(data, 8);
system("pause");
return 0;
}
选择排序
1、思想:将数据放置在数组正确的位置上。
datat[]中有n个数据,在data[]中找到最小值,与data[0]交换;此后在data[1]与data[n-1]中继续找到最小值,与data[1]交换;在data[2]与data[n-1]中继续找到最小值,与data[2]交换。
2、复杂度:O(n^2)
3、缺点:
4、源代码:
#include <iostream>
using namespace std;
template<class T>
void selectionsort(T data[], int n)
{
T tem;
int temi;
for (int j = 0;j < n;j++) {
tem = data[j];
temi = j;
for (int i=j+1;i < n;++i) {//遍历寻找最小值
if (data[i] < tem) {
tem = data[i];
temi = i;
}
}
if (temi != j) {//倘若原先data[j]已在合适的位置,便不在交换
data[temi] = data[j];//交换数组的数值,将最小值放在合适的位置
data[j] = tem;
}
}
}
template<class T>
void printdata(T data[], int n)
{
for (int i = 0;i < n;++i) {//注意,这里不能用i<=n
cout << data[i] << " ";
}
}
int main() {
int data[] = { 10, 165, 12.5, 16, 5.5, 132, 1 ,651 };
selectionsort(data, 8);
printdata(data, 8);
system("pause");
return 0;
}
冒泡排序
1、思想:依次遍历数组,比较相邻的两个元素,如果它们的顺序错误就把它们交换过来,直到没有再需要交换的元素。之所以为冒泡,是因为越小的元素慢慢地往前面冒出来。
2、复杂度:O(n^2)
3、源代码
#include <iostream>
using namespace std;
template<class T>
void bubblesort(T data[], int n)
{
bool is_swap = true;//若在一次遍历中无交换,则说明此时排序已完成
for (int j = 0;j < n - 1 && is_swap;++j) {
is_swap = false;
for (int i = 0;i < n-1;++i) {
if (data[i] > data[i + 1]) {
is_swap = true;
swap(data[i], data[i + 1]);
}
}
}
}
template<class T>
void printdata(T data[], int n)
{
for (int i = 0;i < n;++i) {//注意,这里不能用i<=n
cout << data[i] << " ";
}
}
int main() {
int data[] = { 10, 165, 12.5, 16, 5.5, 132, 1 ,651 };
bubblesort(data, 8);
printdata(data, 8);
system("pause");
return 0;
}
梳排序
1、思想:将待排序序列通过增量分为若干个子序列,然后对子序列进行一趟冒泡排序,一步步减小增量,直至增量为1。
梳排序增量是根据递减率减小的,递减率的设定影响着梳排序的效率,原作者以随机数作实验,得到最有效递减率为1.3的。
2、排序举例
举例:待排序序列为{8, 6, 5, 2, 1, 4, 3,7}
(1)初始increment = 8/1.3 =6。分为子序列{8, 3}{6, 7}{5}{2}{1}{4}进行一趟冒泡排序,得到{3, 6, 5, 2, 1, 4, 8, 7} (每一个子序列在父序列的索引相差increment )
(2)increment = 6/1.3 = 4。分为子序列{3, 1}{6, 4}{5, 8}{2, 7}进行一趟冒泡排序,得到{1, 4, 5, 2, 3, 6, 8, 7}。
(3)increment = 4/1.3 = 3。分为子序列{1, 2, 8}{4, 3, 7}{5, 6}进行一趟冒泡排序,得到{1, 3, 5, 2, 4, 6, 8, 7}。
(4)increment = 3/1.3 = 2。分为子序列{1, 5, 4, 8}{3, 2, 6, 7}进行一趟冒泡排序,得到{1, 2, 4, 3, 5, 6, 8, 7}。
(5)increment = 2/1.3 = 1。分为子序列{1, 2, 4, 3, 5, 6, 8, 7}进行一趟冒泡排序,得到{1, 2, 3, 4, 5, 6, 7, 8}。
3、复杂度:O(nlgn)
4、源代码:
#include <iostream>
using namespace std;
template<class T>
void combsort(T data[], int n)
{
int step=n/1.3;//将索引相差step的元素进行冒泡排序
while (step>1)
{
for (int i = 0;i + step <= n - 1;++i)
if (data[i] > data[i + step])
swap(data[i], data[i + step]);
step = step / 1.3;
}
//最后一次为step为1的冒泡排序
bool is_swap = true;//若在一次遍历中无交换,则说明此时排序已完成
for (int j = 0;j < n - 1 && is_swap;++j) {
is_swap = false;
for (int i = 0;i < n - 1 - j;++i)
if (data[i] > data[i + 1]) {
is_swap = true;
swap(data[i], data[i + 1]);
}
}
}
template<class T>
void printdata(T data[], int n)
{
for (int i = 0;i < n;++i) {//注意,这里不能用i<=n
cout << data[i] << " ";
}
}
int main() {
int data[] = { 10, 165, 12, 16, 5, 132, 1 ,651 };
combsort(data, 8);
printdata(data, 8);
system("pause");
return 0;
}