2-1初级排序算法
概述
-
排序=比较+交换
-
排序算法的模板
#include <iostream> #include <vector> using namespace std; //不同的排序算法 class Soulution { public: void sort(vector<int>& arr) { } //比较两个元素返回较小值 bool less(int num1, int num2) { return num1 < num2; } //交换下标为i和j的两个元素 void exch(vector<int>& arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } //打印数组 void show(vector<int> arr) { for (int i = 0; i < arr.size(); i++) { cout << arr[i] << " "; } } //判断数组是否递增 bool isSort(vector<int> arr) { int n = arr.size(); for (int i = 0; i < n-1; i++) { if(less(arr[i + 1], arr[i])) return false; } return true; } }; //编写主函数 int main() { Soulution *so = new Soulution(); //测试数组 vector<int> arr = { 1,4,9,2,3,7,8,0,5 }; //排序 so->sort(arr); //测试是否有序 cout<<so->isSort(arr)<<endl; //输出排序之后的数组 so->show(arr); }
选择排序
-
算法思想–不断选择剩余元素中的较小者
- 在数组中找到最小的那个元素,将最小的元素和第一个元素交换位置
- 在剩下的元素中最小的元素,和第二个元素交换位置
- 以此类推,直到整个数组排序
-
算法分析–时间复杂度为N^2
- 每次交换确定一个元素,交换的次数是N,算法的效率取决于找到交换元素的比较次数
- 第一趟比较N-1次,第二趟比较N-2次,第i趟比较N-i次
- 所以N次交换需要比较N(N-1)/2次~1/2*(N^2)
- 时间复杂度为N^2
-
特点
- 运行时间和输入无关
- 数据移动是最少的
-
模拟实例 { 1,4,9,2,3,7,8,0,5 }
趟数/下标 0 1 2 3 4 5 6 7 8 原始数组 1 4 9 2 3 7 8 0 5 1 0 1 2 0 1 4 3 0 1 2 9 4 0 1 2 3 9 5 0 1 2 3 4 9 6 0 1 2 3 4 5 7 7 0 1 2 3 4 5 7 8 8 0 1 2 3 4 5 7 8 9 tips:空格表示和上一行保持一致
-
代码实现
#include <iostream> #include <vector> using namespace std; //不同的排序算法 class Soulution { public: void sort(vector<int>& arr) { for (int i = 0; i < arr.size() - 1; i++) { int minIndex = i; for (int j = i + 1; j < arr.size(); j++) { if (less(arr[j], arr[minIndex]))//找到第i轮最小的数 minIndex = j; } exch(arr, minIndex, i);//第i轮最小的数和第i个数交换 } } //比较两个元素返回较小值 bool less(int num1, int num2) { return num1 < num2; } //交换下标为i和j的两个元素 void exch(vector<int>& arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } //打印数组 void show(vector<int> arr) { for (int i = 0; i < arr.size(); i++) { cout << arr[i] << " "; } } //判断数组是否递增 bool isSort(vector<int> arr) { int n = arr.size(); for (int i = 0; i < n-1; i++) { if(less(arr[i + 1], arr[i])) return false; } return true; } }; //编写主函数 int main() { Soulution *so = new Soulution(); //测试数组 vector<int> arr = { 1,4,9,2,3,7,8,0,5 }; //排序 so->sort(arr); //测试是否有序 cout<<so->isSort(arr)<<endl; //输出排序之后的数组 so->show(arr); }
插入排序
-
算法思想—不断把新的元素插入到正确的位置
- 类似于扑克
- 先随机选择一张牌作为第一张牌
- 拿到第二张牌,比第一张牌大就插入到左边,否则插入到右边
- 拿到第三张牌,再找到已经拍好序的前两中排中该插入的位置,然后插入
- 拿到第i张牌,找到已经排好序中的前i-1张牌,插入到对应的位置
-
算法分析–时间复杂度为O(N^2)
-
最坏的情况下
选定一个元素,总共要插入n-1个元素
找第二个元素插入的位置比较1次,需要有n-1个元素后移,交换n-1次
找第三个元素插入的位置比较2次,需要有n-2个元素后移,交换n-2次
找第n个元素插入的位置比较n-1次,需要有1个元素后移,交换1次
所以比较的次数是
(N-1)*(N-1)/2~N*N/2
交换的次数是
(N-1)*(N-1)/2~N*N/2
-
最好的情况下,已经排好序了,交换0次,比较N-1次
-
平均需要
~N^2/4
次交换以及~N^2/4
次比较 -
插入排序在下列情况运用特别有效
- 数组中每个元素距离它最终的位置都不远
- 一个有序的大数组接一个小数组
- 数组中只有几个元素的位置不正确
-
-
模拟排序
趟数/初始值 S O R T E X A M P L E 1 O S 2 O R S 3 O R S T 4 E R O S T 5 E R O S T X 6 A E O S T O X 7 A E M O R S T X 8 A E M O P R S T X 9 A E L M O P R S T X 10 A E E L M O P R S T X -
代码
- 交换实现插入排序
#include <iostream> #include <vector> using namespace std; //不同的排序算法 class Soulution { public: void sort(vector<char>& arr) { int n = arr.size(); for (int i = 1; i < n ; i++)//从1号位置上的数开始,一直到最后一个数 { for (int j = 0; j < i; j++)//寻找插入的位置,下标应该为0到i-1 { if (less(arr[i], arr[j])) //比较要插入的数和排序好的数,如果要插入的数比排序好的数大就换位置 exch(arr, i, j); } } } //比较两个元素返回较小值 bool less(char num1, char num2) { return num1 < num2; } //交换下标为i和j的两个元素 void exch(vector<char>& arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } //打印数组 void show(vector<char> arr) { for (int i = 0; i < arr.size(); i++) { cout << arr[i] << " "; } } //判断数组是否递增 bool isSort(vector<char> arr) { int n = arr.size(); for (int i = 0; i < n-1; i++) { if(less(arr[i + 1], arr[i])) return false; } return true; } }; //编写主函数 int main() { Soulution *so = new Soulution(); //测试数组 vector<char> arr = {'S','O','R','T','E','X','A','M','P','L','E'}; //排序 so->sort(arr); //测试是否有序 cout<<so->isSort(arr)<<endl; //输出排序之后的数组 so->show(arr); }
-
向后移动实现插入排序
#include <iostream> #include <vector> using namespace std; //不同的排序算法 class Soulution { public: void sort(vector<char>& arr) { int n = arr.size(); for (int i = 1; i < n ; i++)//从1号位置上的数开始,一直到最后一个数 { for (int j = 0; j < i; j++)//寻找插入的位置,下标应该为0到i-1 { if (less(arr[i], arr[j]))//比较要插入的数和排序好的数,如果要插入的数比排序好的数大,从这个数开始到插入的数原来的位置向后移动 { int temp = arr[i]; //保存插入的数 for (int k = i; k >j; k--) { arr[k] = arr[k - 1]; } arr[j] = temp;//把元素插入到正确位置上 break; } } } } //比较两个元素返回较小值 bool less(char num1, char num2) { return num1 < num2; } //交换下标为i和j的两个元素 void exch(vector<char>& arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } //打印数组 void show(vector<char> arr) { for (int i = 0; i < arr.size(); i++) { cout << arr[i] << " "; } } //判断数组是否递增 bool isSort(vector<char> arr) { int n = arr.size(); for (int i = 0; i < n-1; i++) { if(less(arr[i + 1], arr[i])) return false; } return true; } }; //编写主函数 int main() { Soulution *so = new Soulution(); //测试数组 vector<char> arr = {'S','O','R','T','E','X','A','M','P','L','E'}; //排序 so->sort(arr); //测试是否有序 cout<<so->isSort(arr)<<endl; //输出排序之后的数组 so->show(arr); }
希尔排序
-
算法思想
使得数组中任意间隔为h的元素都是有序的
-
算法分析
目前来说理解希尔排序的性能还是一项挑战
-
模拟排序
选择不同的间隔,排序的方式会不一样,可参考哔哩哔哩视频
-
代码实现
以插入间隔每次减少一半为例,inc表示这一轮的间距
#include <iostream> #include <vector> using namespace std; //不同的排序算法 class Soulution { public: void sort(vector<char>& arr) { int n = arr.size(),j=0; //设置哈希排序的增量 for (int inc = n / 2; inc > 0; inc = inc / 2) { //插入排序,顺序为第一个数到最后一个数,依次在所在的组进行希尔排序 for (int i = inc; i < n; i++) { int temp = arr[i]; for (j = i; j >= inc&& less(temp, arr[j-inc]); j=j-inc) { arr[j] = arr[j - inc]; } arr[j] = temp; } } } //比较两个元素返回较小值 bool less(char num1, char num2) { return num1 < num2; } //交换下标为i和j的两个元素 void exch(vector<char>& arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } //打印数组 void show(vector<char> arr) { for (int i = 0; i < arr.size(); i++) { cout << arr[i] << " "; } } //判断数组是否递增 bool isSort(vector<char> arr) { int n = arr.size(); for (int i = 0; i < n-1; i++) { if(less(arr[i + 1], arr[i])) return false; } return true; } }; //编写主函数 int main() { Soulution *so = new Soulution(); //测试数组 vector<char> arr = {'S','O','R','T','E','X','A','M','P','L','E'}; //排序 so->sort(arr); //测试是否有序 cout<<so->isSort(arr)<<endl; //输出排序之后的数组 so->show(arr); }