一、选择排序法
1.1 可看可不看
在了解这三种排序算法前,先解释一个概念:墙(wall)。
- 在这三中排序算法中,为了区分已排序序列与未排序序列,于是我们设置一堵墙把它们区分开来。
- 这堵墙的具体表现形式为它限制了排序的可操作范围,在程序中表现为在循环中变量的取值范围。
如:
for (i = 0; i < n; i++)
{
for (j = i + 1; j < n; j++)
{
//......
}
}
在这段代码中,随着i的变化,每次j的初值都会发生变化,内层循环的次数也发生了变化。这个过程就像一堵无形的墙在不断移动,从而限制了行动。(这个概念不急于理解,观看以下内容,便不难理解)
1.2 算法描述
1.2.1 算法思想
选择排序的基本思想是:每一趟在n-i+1(i=1,2,…n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录。
简单来讲,给定n个无序的数
第一趟:在这n个数中求得最小值,将其放在序列最左边。
第二趟:在除第一个已排列好的数外的其它n-1个数继续求最小值,放在第二个位置。
第三躺:在除已排列好的两个数外的其它n-2个数中求最小值,放在第三个位置。
…
1.2.2 动图演示
1.2.3 例子
以下例子中的 “{” 就相当于是墙,墙左边是已排序部分,墙右边是未排序部分。
0 | 初始序列:{ 49 27 65 97 76 12 38 } |
---|---|
1 | 12与49交换:12 { 27 65 97 76 49 38 } |
2 | 27不动 :12 27 { 65 97 76 49 38 } |
3 | 65与38交换:12 27 38 { 97 76 49 65 } |
4 | 97与49交换:12 27 38 49 { 76 97 65 } |
5 | 65与76交换:12 27 38 49 65 { 97 76 } |
6 | 97与76交换:12 27 38 49 65 76 97 |
1.2.4 流程图
1.2.5 代码示例
void selection(int a[], int n)
{
int i, j, temp;
for (i = 0; i < n; i++)
{
for (j = i + 1; j < n; j++)
{
if (a[i] > a[j])
{
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
}
二、冒泡排序法
2.1算法思想
1.比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2.对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。
3.在这一点,最后的元素应该会是最大的数。
4.针对所有的元素重复以上的步骤,除了最后一个。
5.持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较
2.2 动图演示
2.3 例子
从左往右排序和从右往左排序都可行,以下例子为从右到左排序。
0 | 原始序列: { 23,78,45,8,32,56 } |
---|---|
1.1 | 45与8交换:{ 23 78 8 45 32 56 } |
1.2 | 78与8交换:{ 23 8 78 45 32 56 } |
1.3 | 23与8交换:8 { 23 78 45 32 56 } |
2 | 8 23 { 32 78 45 56 } |
3 | 8 23 32 { 45 78 56 } |
4 | 8 23 32 45 { 56 78 } |
5 | 8 23 32 45 56 78 |
2.4 流程图
以下流程图中出现的概念与上一张相同。
2.5 代码示例
void bubble(int a[], int n)
{
int i, j,temp;
for (i = 0; i < n - 1; i++)
{
for (j = 0; j < n - 1 - i; j++)
{
if (a[j] > a[j + 1])
{
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
}
三、插入排序法
3.1算法描述
1.从第一个元素开始,该元素可以认为已经被排序
2.取出下一个元素,在已经排序的元素序列中从后向前扫描
3.如果该元素(已排序)大于新元素,将该元素移到下一位置
4.重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
5.将新元素插入到该位置后
6.重复步骤2~5
插入排序法的步骤就像我们平时玩卡牌游戏的时候对卡牌进行排序的步骤:拿出一张牌,寻找正确的位置插入。
3.2 动图演示
3.3 例子
0 | 原始序列: 23 { 78 45 8 32 56 } |
---|---|
1 | 23 78 { 45 8 32 56 } |
2 | 23 45 78 { 8 32 56 } |
3 | 8 23 45 78 { 32 56 } |
4 | 8 23 32 45 78 {56} |
5 | 8 23 32 45 56 78 |
3.4 流程图
注: Found 起标记作用,用来判断是否需要执行内循环。
3.5 代码示例
void insert(int a[], int n)
{
for (int i = 1; i < n; i++)
{
int temp = a[i], j;
for (j = i; j > 0 && temp < a[j - 1]; j--)
{
a[j] = a[j - 1];
}
a[j] = temp;
}
}