1、冒泡排序法(实质为滤遍数组交换位置)
以函数的形式补充几点(从小到大)
假设给定的是数组
void bubble(int a[], int size) 两个参数,第一个传递数组(指针)
{
for(int pass = 1; pass < size; pass++) 从第二个数开始,每个数都要循环一次
{
for (int i = 0; i < size; i++) 每排好一个数,滤遍数组元素减一
{
if (a[pass] < a[i])
{
int temp = a[i];
a[i] = a[pass];
a[pass] = temp;
}
}
}
}
记得有两个for循环;还有 if 的 < 换成 > 就是从大到小
2、插入排序法(实质为元素后移插入位置)
以函数的形式补充几点(从小到大)
void isort(int a[], int size)
{
for (int i = 1; i < size; i++) 除第一个数都要插入一次,共循环(size - 1)次
{
int ins = a[i], idx = i - 1; ins是要插入的数,idx是从这个数往前一位的数
for (; idx >= 0 && ins < a[idx]; idx--) 从idx开始往前一直往后移位置
{ 直到找到比一个idx比ins小,将ins插到idx前面
a[idx + 1] = a[idx]; 往后移
}
a[idx + 1] = ins; 插入
}
}
注意逻辑,理解起来就不难了;还有第二个for循环的第二个参数是 < 排序就是从小到大,反之亦然
3、快速排序法(实质为冒泡排序法的改进)
为什么说实质为冒泡排序法的改进?因为与冒泡排序相比,每次的交换是跳跃式的,每次排序的时候设置一个基准点,将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数全部放到基准点的右边。这样在每次交换的时候就不会像冒泡排序一样每次只能在相邻的数之间进行交换,交换的距离就大的多了。因此总的比较和交换次数就少了,速度自然就提高了 (通常为了方便,以第一个数作为基准数)
以函数的形式补充几点(从小到大)
void qsort(int a[], int begin, int end) 可以选择要排序的位置
{
if (begin > end) 防止出错
return;
int tmp = a[begin]; 基准点
int i = begin;
int j = end;
while (i != j)
{
while (a[j] >= tmp && j > i) 防止 i 跑到 j 右边去,故要判断 j > i
j--;
while (a[i] <= tmp && j > i) 防止 i 跑到 j 右边去,故要判断 j > i
i++;
int t = a[i]; 交换 i 与 j 的位置
a[i] = a[j];
a[j] = t;
}
a[begin] = a[i]; 此时 i 与 j 位于同一位置,将此元素与基准点交换位置
a[i] = tmp; (如果看不懂可以将这两个表达式与上面的 tmp 赋值一起看,
相当于tmp充当临时变量,为了使位于同一位置的元素与基准点交换位置)
qsort(a, begin, i - 1); 左边再来一遍
qsort(a, i + 1, end); 右边再来一遍
}
警示:里面两个 while 的位置不能换,因为基准点是位于左边的, j 会先跑到 i 的位置,因此 i 和 j 一定会同时处于小于等于基准点的元素上(避免于基准点交换位置之后,左边出现比基准点大的元素)
注意两个while中是 >= 与 <= ;还有最后记得代入的是位置(begin),而不是元素( a [begin] )
更详细的说明在这里 快速排序法(详解),这篇博客可能更适合初学者叭~
4、sort()函数(比冒泡之类的排序算法效率要高)
包含在头文件为#include< algorithm >中
以函数的形式举例,实现的是从小到大(升序)排列;再加一个函数compare()作为第三个参数则实现从大到小(降序)排列
bool compare(int a,int b)
{
return a>b;
}
int a[10]={9,6,3,8,5,2,7,4,1,0};
for(int i=0;i<10;i++)
cout<<a[i]<<" ";
sort(a,a+10); //传递的参数是地址
for(int i=0;i<10;i++)
cout<<a[i]<<" ";
sort(a,a+10,compare); //在这里就不需要对 compare函数传入参数了
for(int i=0;i<10;i++)
cout<<a[i]<<" ";
Output:
原数组
9 6 3 8 5 2 7 4 1 0
从小到大
0 1 2 3 4 5 6 7 8 9
从大到小
9 8 7 6 5 4 3 2 1 0
5、数组引用:Josephus问题的简化
有 10 个人围坐在圆桌周围,现在从第 1 个人开始报数,数到第 interval 的人出列,然后从出列的下一个人重新开始报数,数到第 interval 的人又出列,如此重复直到所有的人全部出列为止
当输入 interval 后,求最后胜出的人(打印其下标)
#include <iostream>
using namespace std;
int main()
{
const int num = 10;
int a[num];
for (int i = 0; i < num; i++)
{
a[i] = i + 1;
}
cout << "几个小孩算一轮:";
int interval;
cin >> interval;
for (int i = 0; i < num; i++)
{
cout << a[i] << ",";
}
cout << endl;
int i = -1; //保证数第一个数是从第一个人开始数的
for (int k = 1; 1; k++) //轮数,num-1 轮(为了剩下一个人)
{
for (int j = 0; j < interval;) //每数 interval 个数淘汰一个人
{
i = (i + 1) % num; //取模是为了保证淘汰人的下标永远在 num 的范围内
if (a[i] != 0) //跳过淘汰的人,
{
j++;
}
}
if (k == num) //判断结束
{
break;
}
cout << a[i] << ",";
a[i] = 0;
}
cout << endl;
cout << a[i] << "赢了";
return 0;
}
Input
几个人算一轮:3
Output
1,2,3,4,5,6,7,8,9,10, 这是原排列顺序
3,6,9,2,7,1,8,5,10, 这是淘汰人的顺序
4赢了 winner
这个不要想的太复杂了,想的太复杂反而容易想错
核心思想就是:将淘汰的人标记为 0 ,一直循环、标记,直到只剩一个人为止
其实还可以自定义 有多少人 和 从哪个人开始报数 ,详细我的另一篇博客Josephus问题(数组方法)(最简易答案)
阶段性结束,点此进入系列下一篇
| 挑时间看这本书 | 看到什么补什么 | 不定时 | 到一定节点会结束本章新开一章 | 一个系列 | 直到看完这本书 | 划水摸鱼|