1.排序的概念
排序是计算机内经常进行的一种操作,其目的是将一组“无序”的记录序列调整为“有序”的记录序列。
排序分为内部排序和外部排序。若整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序。反之,若参加排序的记录数量很大,整个序列的排序过程不可能在内存中完成,则称此类排序问题为外部排序。
2.算法分析
- 插入排序
- 直接插入排序
将第一个和第二个元素排好序,然后将第3个元素插入到已经排好序的元素中,依次类推(插入排序最好的情况就是数组已经有序了)
- 希尔排序
因为插入排序每次只能操作一个元素,效率低。元素个数N,取奇数k=N/2,将下标差值为k的数分为一组(一组元素个数看总元素个数决定),在组内构成有序序列,再取k=k/2,将下标差值为k的数分为一组,构成有序序列,直到k=1,然后再进行直接插入排序。
- 选择排序
- 简单选择排序
选出最小的数和第一个数交换,再在剩余的数中又选择最小的和第二个数交换,依次类推
- 堆排序
以升序排序为例,利用小根堆的性质(堆顶元素最小)不断输出最小元素,直到堆中没有元素
1.构建小根堆
2.输出堆顶元素
3.将堆低元素放一个到堆顶,再重新构造成小根堆,再输出堆顶元素,以此类推
- 交换排序
- 冒泡排序
头尾进行冒泡,每次把最大的沉底,最小的浮上去,两边往中间靠1
- 快速排序
选择一个基准元素,比基准元素小的放基准元素的前面,比基准元素大的放基准元素的后面,这种动作叫分区,每次分区都把一个数列分成了两部分,每次分区都使得一个数字有序,然后将基准元素前面部分和后面部分继续分区,一直分区直到分区的区间中只有一个元素的时候,一个元素的序列肯定是有序的嘛,所以最后一个升序的序列就完成啦。
- 归并排序
将一个无序的数列一直一分为二,直到分到序列中只有一个数的时候,这个序列肯定是有序的,因为只有一个数,然后将两个只含有一个数字的序列合并为含有两个数字的有序序列,这样一直进行下去,最后就变成了一个大的有序数列
- 计数排序
找到最大的数,开个比最大的数大一点的数组,遍历每个元素,某个元素为k,则a[k]++,最好遍历数组a,a[k]等于多少就输出多少个k。只能处理整型数
稳定排序:冒泡排序,直接插入排序,归并排序,计数排序
稳定排序:待排序的记录序列中可能存在两个或两个以上关键字相等的记录。排序前的序列中Ri领先于Rj(即i<j).若在排序后的序列中Ri仍然领先于Rj,则称所用的方法是稳定的。比如int数组[1,1,1,6,4]中a[0],a[1],a[2]的值相等,在排序时不改变其序列,则称所用的方法是稳定的。
不稳定排序:简单选择排序,快速排序,希尔排序,堆排序
3.具体排序讲解
3.1插入排序
直接插入排序
直接插入排序的核心思想就是:将数组中的所有元素依次跟前面已经排好的元素相比较,如果选择的元素比已排序的元素小,则交换,直到全部元素都比较过 因此,从上面的描述中我们可以发现,直接插入排序可以用两个循环完成。
第一层循环:遍历待比较的所有数组元素
第二层循环:将本轮选择的元素(selected)与已经排好序的元素(ordered)相比较。如果:selected > ordered,那么将二者交换。
#include<iostream>
#include<vector>
using namespace std;
void Print(vector<int>& v,int i) {
cout <<"第"<< i <<"次排序结果"<< ":";
for (int j = 0; j<v.size(); ++j) {
cout << v[j] << " ";
}
cout << endl;
}
void InsertSort(vector<int>& v) {
for (int i = 1; i < v.size(); ++i) {
// //若第i个元素大于i-1元素,直接插入。小于的话,移动有序表后插入
if (v[i] < v[i - 1]) {
int end = i - 1;
int tmp = v[i];
while(end>=0) {
if (tmp < v[end]) {
v[end + 1] = v[end];
end--;
}
else
break;
}
v[end + 1] = tmp;
}
Print(v, i);
}
}
int main() {
vector<int> v;
v.push_back(10);
v.push_back(7);
v.push_back(9);
v.push_back(8);
v.push_back(4);
v.push_back(2);
InsertSort(v);
return 0;
}
希尔排序
希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。
希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
算法步骤:
1.选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
2.按增量序列个数k,对序列进行k趟排序;
3.每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
#include<iostream>
#include<vector>
using namespace std;
void Print(vector<int>& v, int i) {
cout << "第" << i << "次排序结果" << ":";
for (int j = 0; j < v.size(); ++j) {
cout << v[j] << " ";
}
cout << endl;
}
void ShellSort(vector<int>& v) {
int size = v.size();
int gap = size;
while (gap > 1) {
gap = gap / 3 + 1;
for (int i = 0; i < size - gap; ++i) {
int end = i;
int tmp = v[end + gap]