【常用排序算法】以最简单的方式理解冒泡排序

(最近一直在看PHP,加上OJ 404了,所以这两天都没有写C,但是还是有在写代码的。)

本人小白,而且脑子笨,理解算法比较困难,现在我把我对排序算法的理解贴出来以便以后复习理解。代码是其他博客里偷的,后面标识出处。

1. 冒泡排序

冒泡排序简单来说就是把当前数字与右边的数字进行比较,如果大,那么就交换位置,否则就把我们盯住的当前值换成右边大的那个数,再和右边的数字比较,于是完成第一轮,实现的结果就是把最大的数放到了最后(这里假设排序规则是是左小右大)。

冒泡排序的特征就是每一轮都找到最大值(或者最小值)。

思想理解

要实现的功能就是将元素像冒泡一样移动。

打个通俗的比方,就假设一个寻宝藏的人,途径一片沙漠,沙漠里埋藏着金银珠宝,他只有两只手只能拿一个箱子的珠宝,那么就要找到装有最多财富的箱子,不断地把找到的箱子和自己拥有的箱子进行比较,如果自己的多,那就不交换。

算法实现:

#include <stdio.h>

// 分类 -------------- 内部比较排序
// 数据结构 ---------- 数组
// 最差时间复杂度 ---- O(n^2)
// 最优时间复杂度 ---- 如果能在内部循环第一次运行时,使用一个旗标来表示有无需要交换的可能,可以把最优时间复杂度降低到O(n)
// 平均时间复杂度 ---- O(n^2)
// 所需辅助空间 ------ O(1)
// 稳定性 ------------ 稳定

void Swap(int A[], int i, int j)
{
    int temp = A[i];
    A[i] = A[j];
    A[j] = temp;
}

void BubbleSort(int A[], int n)
{
    for (int j = 0; j < n-1 ; j++)         // 每次最大元素就像气泡一样"浮"到数组的最后
    {
        for (int i = 0; i < n - 1 - j; i++) // 依次比较相邻的两个元素,使较大的那个向后移
        {
            if (A[i] > A[i + 1])            // 如果条件改成A[i] >= A[i + 1],则变为不稳定的排序算法
            {
                Swap(A, i, i + 1);
            }
        }
    }
}

int main()
{
    int A[] = { 6, 5, 3, 1, 8, 7, 2, 4 };    // 从小到大冒泡排序
    int n = sizeof(A) / sizeof(int);//n表示的是数组元素的个数
    BubbleSort(A, n);
    printf("冒泡排序结果:");
    for (int i = 0; i < n; i++)
    {
        printf("%d ", A[i]);
    }
    printf("\n");
    return 0;
}

分析程序实现

首先BubbleSort里有两个参数,一个是存放一串随机数的数组,还有一个n就是数组元素个数。

然后BubbleSort里有两个for,可能是我对循环了解的还不是特别深入,一开始我并没有理解这段代码,但是把代码还原成最初的双层循环来看,就很清晰了:

#include <stdio.h>
//这是最简单的两层for循环,我们假设上面的n = 10int main(int argc, char* argv[])
{
    for(int j = 0;j < 9;j++)
    {
        for(int i = 0;i < 9 - j;i++)
        {
            printf("%d,%d\t",j,i);

        }
        printf("\n");
    }
}

运行结果:

这里写图片描述

可以看到,里面for循环的变量i从0一直增长到8,第二轮就只增长到7,逐渐减少到0;而外面第一层for循环变量j就是当i跑了一轮之后再增加1,最后增加到了8。

在冒泡排序算法里,变量i代表的就是每个元素在数组里对应的数组下标,数组下标的增长就实现了元素的向右移动。而每过一轮,i增长的终点就减一,意思就是不用再和最后一个数比较(因为最后一个数已经排好序了);
当里面的for循环走了一轮之后开始执行外面的for,也就是变量i完成了第一轮,变量j增一,变量i开始要执行第二轮,总共有9个数(n=10),那么就要执行9轮比较,因此就对应了j从0增长到8。

算法复杂度分析

1.最好的情况:

当数串已经排好序,即正序。
T(n) = O(n)

2.最坏的情况:

当数串是反序。
T(n) = O(n^2)

3.平均时间复杂度:

T(n) = O(n2)

4.稳定性

所谓稳定性就是说之后的排序会不会打乱之前的顺序。
对于冒泡排序,原本是稳定的排序算法,如果将记录交换的条件改成A[i] >= A[i + 1],则两个相等的记录就会交换位置,从而变成不稳定的排序算法。

改进算法:鸡尾酒排序

所谓鸡尾酒排序就是先从左到右把最大的放在最右,回来的时候把最小的带到最左边。(这个还是比较容易理解)

算法实现:

#include <stdio.h>

// 分类 -------------- 内部比较排序
// 数据结构 ---------- 数组
// 最差时间复杂度 ---- O(n^2)
// 最优时间复杂度 ---- 如果序列在一开始已经大部分排序过的话,会接近O(n)
// 平均时间复杂度 ---- O(n^2)
// 所需辅助空间 ------ O(1)
// 稳定性 ------------ 稳定

void Swap(int A[], int i, int j)
{
    int temp = A[i];
    A[i] = A[j];
    A[j] = temp;
}

void CocktailSort(int A[], int n)
{
    int left = 0;                            // 初始化边界
    int right = n - 1;
    while (left < right)
    {
        for (int i = left; i < right; i++)   // 前半轮,将最大元素放到后面
        {
            if (A[i] > A[i + 1])
            {
                Swap(A, i, i + 1);
            }
        }
        right--;
        for (int i = right; i > left; i--)   // 后半轮,将最小元素放到前面
        {
            if (A[i - 1] > A[i])
            {
                Swap(A, i - 1, i);
            }
        }
        left++;
    }
}

int main()
{
    int A[] = { 6, 5, 3, 1, 8, 7, 2, 4 };   // 从小到大定向冒泡排序
    int n = sizeof(A) / sizeof(int);
    CocktailSort(A, n);
    printf("鸡尾酒排序结果:");
    for (int i = 0; i < n; i++)
    {
        printf("%d ", A[i]);
    }
    printf("\n");
    return 0;
}

最后小感想:

两层循环是一个经典的二维实现方法,可以解决许多受两个变量控制的问题。经典的有输出金字塔,九九乘法表,二维数组,五子棋棋盘等。

参考文章:http://www.cnblogs.com/eniac12/p/5329396.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值