算法(二)初等排序前篇[插入和冒泡排序]

相关文章

算法(一)时间复杂度

前言

排序是算法的基础,排序有很多种方法,有些方法实现起来很简单,但是效率较差,我们可以将这些排序的方法称之为初等排序。这篇文章我们就来学习初等排序中的插入排序和冒泡排序。

1.插入排序

插入排序比较容易想到,思路与打扑克时排列牌的顺序是类似的。比如我们左手拿牌,然后用右手将牌从左到右,从小到大来排序,这就需要我们把需要进行排列的牌抽出来放到合适的位置,并且不断的重复,直到牌的顺序排好,这个过程就可以理解为插入排序。

图解插入排序

插入排序过程中会将需要排序的数组,分为两个部分:已排序部分和未排序部分,如下图所示。

从图中可以看出这个数组分为两个部分,其中下标为0、1、2的元素为已排列部分,其余的则为未排列部分。

插入的排序规则:

将开头元素视为以排序部分。接着执行如下的处理,直到没有未排序部分。

- 取出未排序部分的开头元素赋值给临时保存数据的变量v。

- 在已排列的部分将所有比v大的元素向后移动一个位置。

- 将取出的元素v插入空位。

按照这个规则,我们来举一个简单的例子。我们对数组 a={8,3,1,5,2,1} 进行从小到大排序,数组a如下图所示。

我们对数组a进行排序,共需要5个步骤:

1.接着我们将a[0]=8视为已排序,我们从a[1]开始操作,将a[1]的值3取出,3要小于a[0]的值8,因此将a[0]的值8移动到a[1],再把3插入到a[0],如下图所示。

2.a[2]的值1要比a[0]和a[1]的值要小,则将a[0]和a[1]顺次向后移一个位置,然后将1插入a[0],如下图所示。

3.将a[3]中的5拿出来,比它大的是a[2]的8,因此8向后移,将5插入a[3]。如下图所示。

4.将a[4]中2拿出来,发现a[1]、a[2]、a[3]中的值都比2大,因此将它们依次向后移,将2插入到a[1]中,如下图所示。

5.最后将a[5]中的1移到合适的位置,过程和上面一样,最后的排序结果如下图所示。

实现插入排序

接下来要实现插入排序,针对下图来定义变量。

如上图所示,i代表未排序部分的开头元素,v是临时保存a[i]值的变量, j代表已排序部分v要插入的位置。

根据定义的这三个变量,插入排序的实现思路就是:外层循环i从1开始自增,并在每次循环开始时将a[i]的值保存在v中;内层循环则是j从i-1开始向前自减,并将比v大的元素从a[j]移动到a[j+1],并将v插入到当前j+1的位置(内层循环后j会先自减1,因此插入的地方则是j+1的位置),当j等于-1或者a[j]小于等于v则内层循环结束。

接下来我们用代码来实现插入排序,如下所示。


public class InsertSort {
    public static void main(String[] args) {
        int a[] = {8, 3, 1, 5, 2, 1};
        ArrayUtils.printArray(a);
        int b[] = insert(a);
        ArrayUtils.printArray(b);
    }

    public static int[] insert(int[] a) {
        int i, j, v;
        int n = a.length;
        for (i = 1; i < n; i++) {
            v = a[i];
            j = i - 1;
            while (j >= 0 && a[j] > v) {
                a[j + 1] = a[j];
                j--;
            }
            a[j + 1] = v;
        }
        return a;
    }
}

其中负责打印数组的ArrayUtils类如下所示。

public class ArrayUtils {
    public static void printArray(int[] array) {
        System.out.print("{");
        int len=array.length;
        for (int i = 0; i < len; i++) {
            System.out.print(array[i]);
            if (i < len - 1) {
                System.out.print(", ");
            }
        }
        System.out.println("}");
    }
}

输出结果为:

{8, 3, 1, 5, 2, 1}

{1, 1, 2, 3, 5, 8}

插入排序的复杂度

根据算法(一)时间复杂度所讲的,我们来算一下插入排序的时间复杂度。在最坏的情况下,每个i循环都需要执行i次移动,总共需要1+2+……+n-1=n2/2+n/2,根据此前讲过的推导大O阶的规则的我们得出插入排序的时间复杂度为O(n2)。

2.冒泡排序

冒泡排序应该是开发者最容易理解的排序算法,它的基本思想就是每次比较两个相邻的元素,如果它们的顺序错误就把它们交换过来。需要进行排序的元素则向水中的气泡一样慢慢的移向水面。

图解冒泡排序

与插入排序一样,需要进行冒泡排序的数组也分为已排序部分和未排序部分。

冒泡排序的规则为:从数组末尾开始依次比较相邻的两个元素,如果大小关系相反则交换位置,直到数组中不再有顺序相反的相邻元素。

我们对数组 a={5,3,2,4,1} 进行从小到大排序,排序过程如下所示。

第一轮排序:

我们将数组末尾的a[4]的值和a[3]的值进行对比,发现a[4]的值比a[3]的值小,则将它们交换,再接着对剩下的相邻的两个元素进行对比和交换,最终得到的结果为a={1,5,3,2,4},已排序的部分的元素为1。

第二轮排序:

首先对比a[3]和a[4]的值,发现a[3]的值比a[4]的值小,则不需要进行排序。最终得到的结果为a={1,2,5,3,4},已排序部分的元素为1、2。

第三轮排序:

经过第三轮排序,已排序部分的元素为1、2、3。

第四轮排序:

经过四轮排序我们最终得到的结果为a={1,2,3,4,5}

实现冒泡排序

实现插入排序时,我们要先定义两个变量,i为循环变量,表示未排序部分的开头元素,从数组开头向末尾移动。j也为循环变量,用于对未排序部分中相邻元素两两比较,从数组的末尾n-1开始减小到 i 结束(i=1)。

代码实现如下所示。

public class BubbleSort {
    public static void main(String[] args) {
        int a[] = {5, 3, 2, 4, 1};
        ArrayUtils.printArray(a);
        int b[] = bubble(a);
        ArrayUtils.printArray(b);
    }

    public static int[] bubble(int[] a) {
        int i, j, v;
        int n = a.length;
        for (i = 1; i <= n - 1; i++) {
            for (j = n - 1; j >= i ; j--) {
                if (a[j] < a[j - 1]) {
                    v = a[j];
                    a[j] = a[j - 1];
                    a[j - 1] = v;
                }
            }
        }
        return a;
    }
}

其中ArrayUtils的printArray方法此前讲过,这里就不再给出,打印结果为:

{5, 3, 2, 4, 1}

{1, 2, 3, 4, 5}

冒泡排序的复杂度

最坏的情况下,冒泡排序对未排序部分的相邻元素进行了(n-1)+(n-2)+(n-3)+……+1次比较,也就是n2/2+n/2次比较,根据推导大O阶的规则我们得出冒泡排序的时间复杂度为O(n2)。

github源码



欢迎关注我的微信公众号,第一时间获得博客更新提醒,以及更多成体系的Android相关技术干货。

扫一扫下方二维码即可关注:

时间: 2024-09-30 09:51:30

算法(二)初等排序前篇[插入和冒泡排序]的相关文章

[数据结构与算法]二叉排序(搜索)树实现

声明:原创作品,转载时请注明文章来自SAP师太技术博客:www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将追究法律责任!原文链接:http://www.cnblogs.com/jiangzhengjun/p/4289804.html 定义 二叉排序树又称二叉查找树或二叉搜索树,它或者是一棵空树,或者是具有如下性质的二叉树:1.若它是左子树非空,则左子树上所有节点的值均小于根节点的值2.若它的右子树非空,则右子树上所有节点的值均大于根节点的值3.左.

[排序算法二]选择排序

选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾.以此类推,直到全部待排序的数据元素的个数为零.选择排序是不稳定的排序方法. 算法性能 时间复杂度:O(n^2),总循环次数 n(n-1)/2.数据交换次数 O(n),这点上来说比冒泡排序要好,因为冒泡是把数据一位一位的移上来,而选择排序只需要在子循环结束后移动一次

白话经典算法系列 - 七大排序总结篇

原文链接: http://blog.csdn.net/MoreWindows/article/category/859207 1.冒泡排序 核心思路: 双重循环 外层是进行多少轮,一轮冒泡只能排好一个数,所以有n轮:(这是最好的理解方式) 内层是单次冒泡,冒泡的核心是逐个,相邻元素两两比较,如此,一轮冒泡后,最大(最小)元素就跑到最后面了 //核心代码 void sort(int *a, int len) { for (int i = 0; i < len; i++) for (int j =

排序算法(二)选择排序---堆排序

概念:利用树结构进行排序. 分类:1.大顶堆: 每个小树的根节点都大于子节点   升序排序使用大顶堆 2.小顶堆:每个小树的子节点都大于根节点 降序排序使用小顶堆 1 public class HeapSort { 2 3 public static void main(String[] args){ 4 int[] arr=new int[]{9,6,7,0,1,10,4,2}; 5 System.out.println(Arrays.toString(arr)); 6 heapSort(ar

【算法】【排序】【插入类】希尔排序 ShellSort

#include<stdio.h> #include <time.h> #include<stdlib.h> int main(){ int a[15]; //设立随机数 srand(time(0)); for(int i=0;i<15;i++){ a[i]=rand()%(30); //随机数范围0到29之间 } //数组a的大小 int size=sizeof(a)/4; //打印数组信息 for(int i=0;i<size;i++){ printf(

数组的常用算法二之排序算法

冒泡排序冒泡排序从小到大排列 public class TestArray { public static void main(String[] args){ //冒泡排序从小到大排列 int[] a=new int[]{54,78,4,87,75}; for (int i=0;i<a.length-1;i++){ for (int j=0;j<a.length-1-i;j++){ if (a[j]>a[j+1]){ int temp=a[j]; a[j]=a[j+1]; a[j+1]=

二叉排序

二叉排序,附带插入,查找和删除值.. /* Author: buer Date: 2017/9/18 11:56:02 */ #include <stdio.h> #include <stdlib.h> typedef struct Tree { int data; struct Tree *lchild; struct Tree *rchild; }Tree; void createBiTree(Tree *root); void insertData(Tree *root, i

数据结构基础 排序算法(一) 概念篇

本辑将会对笔试面试最常涉及到的12种排序算法(包括插入排序.二分插入排序.希尔排序.选择排序.冒泡排序.鸡尾酒排序.快速排序.堆排序.归并排序.桶排序.计数排序和基数排序)进行详解.每一种算法都有基本介绍.算法原理分析.图解演示.算法代码.笔试面试重点分析.笔试面试题等板块. 一.插入排序 1)算法简介 插入排序(Insertion Sort)的算法描述是一种简单直观的排序算法.它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入.插入排序在实现上,通常

排序算法之简单排序(冒泡、选择、插入)

1.基本概念 内部排序和外部排序 根据排序过程中,待排序的数据是否全部被放在内存中,分为两大类: 内部排序:指的是待排序的数据存放在计算机内存中进行的排序过程: 外部排序:指的是排序中要对外存储器进行访问的排序过程. 内部排序是排序的基础,在内部排序中,根据排序过程中所依据的原则可以将它们分为5类:插入排序.交换排序.选择排序.归并排序:根据排序过程的时间复杂度来分,可以分为简单排序.先进排序.冒泡排序.简单选择排序.直接插入排序就是简单排序算法. 评价排序算法优劣的标准主要是两条:一是算法的运