排序算法四:交换排序之冒泡排序

排序算法四:交换排序之冒泡排序



声明:引用请注明出处http://blog.csdn.net/lg1259156776/


引言

在我的博文《“主宰世界”的10种算法短评》中给出的首个算法就是高效的排序算法。本文将对排序算法做一个全面的梳理,从最简单的“冒泡”到高效的堆排序等。

系列博文的前三篇讲述了插入排序的三种不同类型,本文讲述第二大类的排序算法:交换排序,包括冒泡排序和快速排序


排序相关的的基本概念

  • 排序:将一组杂乱无章的数据按一定的规律顺次排列起来。

    • 数据表( data list): 它是待排序数据对象的有限集合。
    • 排序码(key):通常数据对象有多个属性域,即多个数据成员组成,其中有一个属性域可用来区分对象,作为排序依据。该域即为排序码。每个数据表用哪个属性域作为排序码,要视具体的应用需要而定。
  • 分类
    • 内排序:指在排序期间数据对象全部存放在内存的排序;
    • 外排序:指在排序期间全部对象个数太多,不能同时存放在内存,必须根据排序过程的要求,不断在内、外存之间移动的排序。

排序算法的分析

排序算法的稳定性

如果在对象序列中有两个对象r[i]和r[j] ,它们的排序码k[i]==k[j] 。如果排序前后,对象r[i]和r[j] 的相对位置不变,则称排序算法是稳定的;否则排序算法是不稳定的。

排序算法的评价

时间开销

  • 排序的时间开销可用算法执行中的数据比较次数与数据移动次数来衡量。
  • 算法运行时间代价的大略估算一般都按平均情况进行估算。对于那些受对象排序码序列初始排列及对象个数影响较大的,需要按最好情况和最坏情况进行估算

空间开销

算法执行时所需的附加存储。


交换排序

交换排序的基本思想是:两两比较待排序记录(数据表)的关键字(排序码),发现两个记录的次序相反时即进行交换,直到没有反序的记录为止。主要包括冒泡排序和快速排序。

冒泡排序

算法思想及步骤

冒泡排序是第一个接触也最容易理解的排序算法,因为就像泡泡一样,最轻的率先“冒”出来占据第一的位置,随后是剩下的最轻的再冒出来,占据第二的位置,就这样一步步冒出来,也就完成了排序。

  1. 对象个数n。最多作最多作n-1趟, i= 0, 2, …, n-1 。
  2. 第i趟中从后向前j= n-1, n-2, ……, i,顺次两两比较。
  3. 比较如果发生逆序,则交换V[j-1] 和V[j]。

总之就是每一趟都是将剩余中最大或最小的数据项排在前面已经“冒”出来的数据表后面,遍历完毕也就实现了排序。

算法分析

最好情况:正序排列,比较次数(KCN):n?1 ; 移动次数(RMN):为0。则对应的时间复杂度为O(n)。

完全正序排列的话,只需一趟就能判定是否有序,如果遍历j之后发现没有发生逆序就说明已经有序,所以,共比较了n?1次,移动0次。

最坏情况:逆序排序,比较次数(KCN):∑n?1i=1(n?i)=n(n?1)2;移动次数(RMN):3∑n?1i=1(n?i)=3n(n?1)2。

完全逆序排序的话,第i都要比较n?i次,而每次比较都要移动3次数据项来交换记录位置。因此总的时间复杂度为O(n2)。

它需要一个附加空间,是一个稳定的排序算法。

冒泡排序的c plus plus实现

#include <iostream>

using namespace std;

void BubbleSort(int a[], int size)
{
    int i,j,k,temp;
    for(i = 0; i < size - 1; i++) {
        for(j=0; j < size - 1; j++) {
            if(a[j] > a[j+1]) {
                temp = a[j+1];
                a[j+1] = a[j];
                a[j] = temp;
            }
        }
        for(k = 0; k < size; k++)
            cout << a[k] <<" ";
        cout << endl;
    }
    int dummy = 1;
}

int main()
{
    int k;
    int a[] = {5,7,1,3,4,9,2,6,8,0};
    const size_t sz = sizeof(a)/sizeof(a[0]);
    for(k = 0; k < sz; k++)
        cout << a[k] <<" ";
    cout << endl;
    cout << "======================" << endl;
    BubbleSort(a,sz);
    cout << "======================" << endl;
    for(k = 0; k < sz; k++)
        cout << a[k] <<" ";
    cout << endl;
}

这里给出的BubbleSort其实可以简化,每趟排序都将最大的冒到了最后,所以最后已经排序的不必再进行比较了,从而可以节省一些比较的次数。改进如下:

void BubbleSort(int a[], int size)
    {
        int i,j,k,temp;
        for(i = 0; i < size - 1; i++) {
            for(j=0; j < size - 1 - i; j++) {////////////////////////改进之处
                if(a[j] > a[j+1]) {
                    temp = a[j+1];
                    a[j+1] = a[j];
                    a[j] = temp;
                }
            }
            for(k = 0; k < size; k++)
                cout << a[k] <<" ";
            cout << endl;
        }
        int dummy = 1;
    }

输出结果如下:

5 7 1 3 4 9 2 6 8 0

//======================

5 1 3 4 7 2 6 8 0 9

1 3 4 5 2 6 7 0 8 9

1 3 4 2 5 6 0 7 8 9

1 3 2 4 5 0 6 7 8 9

1 2 3 4 0 5 6 7 8 9

1 2 3 0 4 5 6 7 8 9

1 2 0 3 4 5 6 7 8 9

1 0 2 3 4 5 6 7 8 9

0 1 2 3 4 5 6 7 8 9

//======================

0 1 2 3 4 5 6 7 8 9

注意到,如果此实现中如果给定的数据已经有序,则并不能实现最好情况中所分析的比较次数,因为并没有设定检测每趟是否发生过数据项的交换,如果没有发生数据交换则说明数据表已经有序,则不必进行下一趟的排序了。因此,可以修改代码为:

void BubbleSort(int a[], int size)
{
    int i,j,k,temp;
    int IsReplaced = 0;
    for(i = 0; i < size - 1; i++) {
        IsReplaced = 0;
        for(j=0; j < size - 1 - i; j++) {
            if(a[j] > a[j+1]) {
                temp = a[j+1];
                a[j+1] = a[j];
                a[j] = temp;
                IsReplaced = 1;
            }
        }

        for(k = 0; k < size; k++)
            cout << a[k] <<" ";
        cout << endl;
        if(IsReplaced==0) break;
    }
    int dummy = 1;
}

通过测试数据int a[] = {0,1,5,4,3,2,6,7,8,9};进行对比:

未添加数据项交换检查标志的数据输出:

0 1 5 4 3 2 6 7 8 9
======================
0 1 4 3 2 5 6 7 8 9
0 1 3 2 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
======================
0 1 2 3 4 5 6 7 8 9
请按任意键继续. . .

添加数据相交换检查标志的数据输出:

0 1 5 4 3 2 6 7 8 9
======================
0 1 4 3 2 5 6 7 8 9
0 1 3 2 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
======================
0 1 2 3 4 5 6 7 8 9
请按任意键继续. . .

从对比中可以看出,通过判断之后能够提前终止一轮一轮的交换排序,减少不必要的比较过程。


2015-9-25 艺少

版权声明:本文为博主原创文章,转载请注明出处http://blog.csdn.net/lg1259156776/。

时间: 2024-10-13 00:52:10

排序算法四:交换排序之冒泡排序的相关文章

常用排序算法实现[交换排序之冒泡排序、快速排序]

相关知识 1. 稳定排序和非稳定排序: 稳定排序算法会依照相等的关键(换言之就是值)维持纪录的相对次序. 如果排序算法是稳定的,就是当有两个有相等关键的纪录R和S,且在原本的列表中R出现在S之前,在排序过的列表中R也将会是在S之前. 2. 内排序和外排序 在排序过程中,所有需要排序的数都在内存,并在内存中调整它们的存储顺序,称为内排序: 在排序过程中,只有部分数被调入内存,并借助内存调整数在外存中的存放顺序排序方法称为外排序. 3.算法分类 排序算法从理论上分为如下几类: (1) 交换排序法:

1)①排序算法之交换排序[1]冒泡排序法

1 #include "iostream" 2 using namespace std; 3 4 //************冒泡排序法********* 5 int bubble_sort(int n,int array[100]){ 6 bool exchange; 7 int i,j,temp; 8 i=1; 9 do{ 10 exchange=false; 11 for(j=n-1;j>=i;j--){ 12 if(array[j]<array[j-1]){ 13

八大排序算法学习笔记:冒泡排序

冒泡排序(Bubble Sort,台湾译为:泡沫排序或气泡排序)是一种简单的排序算法. 它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成.这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端. 算法原理: 比较相邻的元素.如果第一个比第二个大,就交换他们两个. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.在这一点,最后的元素应该会是最大的数. 针对所有

排序算法之交换排序

首先,上脑图. 1.为什么要学习排序算法? 这是算法学习的基础,经典的排序算法有着很广泛的用途,一遍遍的被人所使用.而且,在面试找工作的时候,数据结构中的排序算法,也是一个很重要的基本功,经常会被用人单位拿来出题目. 2.如何学习排序算法? 第一步是理解排序算法的原理,这也是最重要的一步. 第二步就是看经典的算法实现,抠细节一个个理解原理到实现经过了哪些变化. 第三部是用纸把算法实现抄一遍,这个时候会发掘出认识和实际的偏差. 第四步是把算法默写出来,这也是很重要的一步,类似于牛吃了食物之后的反刍

排序算法(1)——冒泡排序

冒泡排序 冒泡排序可以说是最简单的一种排序,当然,复杂度也是最高的 冒泡排序的实现过程:两两之间相互比较,当前者比后者大的时候,两者交换(假设是升序排列). 那么给出简单的冒泡排序算法: #define MAXSIZE 10void swap(SqList *L, int i, int j) { int temp = L->r[i]; L->r[i] = L->r[j]; L->r[j] = temp; } typedef struct { int r[MAXSIZE + 1];

常用排序算法总结1一一冒泡排序

前言 排序算法是一种能将一串数据依照特定排序方式进行排列的一种算法.最常用到的排序方式是数值顺序以及字典顺序. 有效的排序算法在一些算法(例如搜索算法与合并算法)中是重要的,如此这些算法才能得到正确解答.排序算法也用在处理文字数据以及产生人类可读的输出结果.基本上,排序算法的输出必须遵守下列两个原则: 输出结果为递增序列(递增是针对所需的排序顺序而言) 输出结果是原输入的一种排列.或是重组 排序算法分类 在计算机科学所使用的排序算法通常被分类为: 计算的时间复杂度(最差.平均.和最好性能),依据

数据结构之排序算法(二)-冒泡排序及改进

冒泡排序算法需要遍历几次数组.每次遍历都要比较连续相邻的元素,如果某一对相邻元素是降序,则互换它们的值,否则,保持不变.由于较小的值像"气泡"一样逐渐浮想顶部,而较大的值沉向底部,所以叫冒泡排序. 冒泡排序的图解是: 总结一句话就是:连续比较相邻的元素,降序则呼唤.有n个数,共需要比较n-1趟,第i趟,需要比较n-i次. BubbleSort.java public class BubbleSort {//时间复杂度O(n^2) public static void display(i

排序高级之交换排序_冒泡排序

冒泡排序(Bubble Sort,台湾另外一种译名为:泡沫排序)是一种简单的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成.这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端. 冒泡排序对个项目需要O()的比较次数,且可以原地排序.尽管这个算法是最简单了解和实现的排序算法之一,但它对于少数元素之外的数列排序是很没有效率的. 冒泡排序是与插入排序拥有相等的

java 排序算法(一) 冒泡排序、快速排序

冒泡排序 冒泡排序是一种简单的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成.这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端. 冒泡排序的算法实现如下:[排序后,数组从小到大排列] /** * 冒泡排序 * 比较相邻的元素.如果第一个比第二个大,就交换他们两个. * 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.在这一点,最后的元素应该会是最大的