#include <iostream>
#include "Student.h"
#include "SortTestHelper.h"
using namespace std;
/**
* 选择排序算法实现
* @tparam T
* @param arr
* @param n
*/
template<typename T>
void selectionSort(T arr[], int n){
for (int i = 0; i < n; ++i) {
//寻找[i,n)区间里的最小值
int minIndex = i;
for (int j = i+1; j < n; ++j) {
if(arr[j] < arr[minIndex]){
minIndex = j;
}
}
swap(arr[i],arr[minIndex]);
}
}
int main() {
int a[10] = {10,9,8,7,6,5,4,3,2,1};
selectionSort(a,10);
SortTestHelper::printArray(a, 10);
float b[4] = {4.4,3.3,2.2,1.1};
selectionSort(b,4);
SortTestHelper::printArray(b, 4);
string c[4] = {"D","C","B","A"};
selectionSort(c,4);
SortTestHelper::printArray(c, 4);
Student d[4] = {{"D",90},{"C",100},{"B",95},{"A",95}};
selectionSort(d, 4);
SortTestHelper::printArray(d, 4);
return 0;
}
Student.h
//
// Created by kim on 2020-02-02.
//
#ifndef SELECTSORT_STUDENT_H
#define SELECTSORT_STUDENT_H
#include <iostream>
#include <string>
using namespace std;
struct Student{
string name;
int score;
/**
* 重载操作符小于号
* @param otherStudent
* @return
*/
bool operator<(const Student &otherStudent){
return score != otherStudent.score ? score > otherStudent.score : name < otherStudent.name;
}
/**
* 友元函数重载输出操作符<< <br/>
* operator<< is a friend function to ostream and class Student<br/>
* so operator<< has access to all members of ostream and class Student<br/>
* 参见<a href="https://docs.microsoft.com/en-us/cpp/cpp/friend-cpp?view=vs-2019#class-members-as-friends">Class members as friends</a>
*
* @param os
* @param student
* @return
*/
friend ostream& operator<<(ostream &os, const Student &student){
os<<"Student: "<<student.name<<" "<<student.score<<endl;
return os;
}
};
#endif //SELECTSORT_STUDENT_H
template<typename T>
void insertionSort(T arr[], int n){
//i表示当前位置;++i表示从前向后,每次步长1;i<n说明进入循环到条件
for (int i = 0; i < n; ++i) {
//寻找元素arr[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;
}
}
冒泡排序
template<typename T>
void bubbleSort( T arr[] , int n){
bool swapped;
do{
swapped = false;
for( int i = 1 ; i < n ; i ++ )
if( arr[i-1] > arr[i] ){
swap( arr[i-1] , arr[i] );
swapped = true;
}
// 优化, 每一趟Bubble Sort都将最大的元素放在了最后的位置
// 所以下一次排序, 最后的元素可以不再考虑
n --;
}while(swapped);
}
希尔排序
排序思路
希尔排序利用了gap间隔,经过间隔上的数,用插入排序排序
取完第一个间隔后,再往后罗一位取第二个间隔上的数,进行插入排序。
假如有15个数,分4组,即间隔为4,完成上述过程,最后得到一个近乎有序的数组。
然后依次按照间隔为2排序,最后按间隔为1排序。
间隔为1时,就是普通插入排序。
为什么比插入排序快
因为在间隔大的时候,进行比较插入,移动的次数少。
在间隔小的时候,移动的距离也小。
特点
跳着排不稳定,效率比插入排序高。
由于不稳定,所以不重要。但是思路需要理解。
template<typename T>
void shellSort(T arr[], int n){
// 计算 increment sequence: 1, 4, 13, 40, 121, 364, 1093...
int h = 1;
while( h < n/3 )
h = 3 * h + 1;
while( h >= 1 ){
// h-sort the array
for( int i = h ; i < n ; i ++ ){
// 对 arr[i], arr[i-h], arr[i-2*h], arr[i-3*h]... 使用插入排序
T e = arr[i];
int j;
for( j = i ; j >= h && e < arr[j-h] ; j -= h )
arr[j] = arr[j-h];
arr[j] = e;
}
h /= 3;
}
}
目录
[TOC]
为什么要学习O(n^2)的排序算法?
选择排序
每次在当前数组里选择最小的数,与当前第一个位置上的数交换,下一次选择数前,将当前数组的开始位置向后移一位,直到当前位置为最后一位。
基本思路
假设从小到大排序,在下面的数组里找到第一个最小的元素。
经过一轮遍历,找到1是最小的,将1和目前数组的第一个位置上的数8交换位置。
第二轮遍历,找第一个位置后最小的元素,此时是2
将2与第二个位置上的数交换
此时前两个位置已经按顺序排好
下面在从第三个位置开始,再依次遍历,一直往后找最小的元素,找到3。
将3和第三个位置上的数交换位置。
再从剩下的元素中找最下的元素,是4,4和第4个位置上的数交换位置。
再从剩下的元素中找最下的元素,是5。
将5和第5个位置上的数交换位置。
接着,剩下的元素中6最小,和第6个位置上的数交换位置。
然后,7是剩下的最小的数了,不需要动(自己和自己交换)
最后8.
所有文件
main.cpp
Student.h
友元函数参见微软文档
SortTestHelper.h
主要实现(重要)
在一个项目里添加多个
C/C++
可执行文件另外我是用Clion写的实验代码,贴一下Cmake列表文件,在一个项目里添加多个
C/C++
可执行文件。add_executable命令的第一个参数是name,代表编译后的可执行文件的文件名。后面的参数是源文件,支持多个。
插入排序
从第一个位置开始遍历,经过n轮遍历,步长是1.
每次遍历的时候,将当前位置的数插入到他前面的元素中合适的位置。
基本思路
假如对下面的数组进行从小到大排序。
对于第一个位置上的数,不动。
然后第二个位置上的数,6,将它插入到它前面的数中合适的位置,比较6和8,6<8,所以6和8交换位置
遍历到第三个位置,2
将2和它前面的数依次比较,最终确认在如下位置。
然后遍历到第四个位置,3,将3依次和前面的元素比较,最终在如下位置。
后面以此类推。
关键代码
上面的插入排序算法还可以优化空间,
插入排序的改进
基本思路
遍历数组,将当前位置的数先临时保存为e,将当前位置的数,依次和前i位比较,每次比较时,如果当前位置的数e比前一位小,就把前一位数向后移一位,直到当前位置的数比前一位数大并且,停止遍历,且该位置为合适的位置,存放e。
依然对如下数组从小到大排序。
首先,对于第一个位置数8依然保持不变,
遍历到第二个位置时,先把6复制一份,然后考虑6适不适合在当前位置。就是和它前面的数依次比较
由于6比8小,所以当前位置应该是8,所以,先将8往后移一位。
再考虑6是不是应该放在前一个位置
由于此时在第0个位置,不需要再比较,那么6就在该位置。把6放在这个位置。
接着遍历到第三个位置,2,将2复制一份。
将2和其前面位置的8比较,2<8,将8往后移一位。
再比较2和6的大小,2<6,此时再把6往后移一位
此时再往前没有数要比较了,所以2就在当前第0个位置,直接将第0个位置赋值为2。
再遍历到第4个位置,复制一份3
然后,依次比较3和8,3<8,8向后移一位,再比较3和6,3<6,6向后移一位。再比较3和2,3>2,所以3就在第二个位置,将3复制给第二个位置。
后面以此类推。
关键代码(重要)
冒泡排序
希尔排序
排序思路
希尔排序利用了gap间隔,经过间隔上的数,用插入排序排序
取完第一个间隔后,再往后罗一位取第二个间隔上的数,进行插入排序。
假如有15个数,分4组,即间隔为4,完成上述过程,最后得到一个近乎有序的数组。
然后依次按照间隔为2排序,最后按间隔为1排序。
间隔为1时,就是普通插入排序。
为什么比插入排序快
因为在间隔大的时候,进行比较插入,移动的次数少。
在间隔小的时候,移动的距离也小。
特点
跳着排不稳定,效率比插入排序高。
由于不稳定,所以不重要。但是思路需要理解。