算法手记(5)初级排序算法

排序是将一组对象按照一定的规则重新排列的过程。即使目前完全可以使用标准库中的排序函数,学习排序算法仍然有着较大意义:
   排序算法的学习可以帮助你全面了解比较算法性能的方法;

类似的技术上能有效解决其他类型的问题;

排序算法通常是我们解决问题的第一步;

更重要的是这些算法都很经典,优雅和高效。

排序在商业数据处理分析和现代科学中占有重要的地位,其中快速排序算法被誉为20世纪科学和工程领域十大算法之一。今天我们要看的就是相对简单但很经典的初级排序算法,包括选择排序,插入排序及Shell排序。

准备

开始之前,我们先约定好算法类模版形式,其中我们将排序代码放入sort()方法中,less()方法对元素进行比较返回bool值,exch()方法用于元素位置交换,形式如下:

public class Example
    {
        public static void sort(IComparable[] a)
        {
            //排序代码
        }

        private static void exch(IComparable[] a, int i, int j)
        {
            IComparable temp = a[i];
            a[i] = a[j];
            a[j] = temp;
        }

        private static bool less(IComparable v, IComparable w)
        {
            return v.CompareTo(w)<0;
        }
        private static void show(IComparable[] a)
        {
            //打印数据
        }
        private static bool isSorted(IComparable[] a)
        {
            for(int i=1;i<a.Length;i++)
            {
                if(less(a[i], a[i-1])) return false;
            }
            return true;
        }
    }

这里我使用C#实现,less()方法使用IComparable接口方法,适用于任何任何实现IComparable接口的数据类型进行排序,系统的Int, String等类型均实现了此接口。

选择排序

概述:

首先找到数组最小的元素,将它和数组第一个元素交换位置。再次,在剩下的元素中找出最小的元素,将它与第二个元素位置交换。如此往复,直到将整个数组排序。因为它不断地选择剩余元素之中的最小者,所以称为选择排序。

分析:

对于长度为N的数组,选择排序需要大约(N^2)/2次比较和N次交换。其增长数量级为平方级别,是一种很容易理解和实现的简单排序算法。它有两个鲜明的特点:

1.运行时间和输入无关。通过实验发现输入一个有序数组和输入一个随机数组所有排序时间竟然一样长。

2.数据移动是最少的。选择排序只有N次交换,这是其他排序算法无法做到的。

代码实现:

public class Selection
    {

        public static void sort(IComparable[] a)
        {
            //排序代码
            for (int i = 0; i < a.Length; i++)
            {
                int min = i;
                for (int j = i + 1; j < a.Length; j++)
                {
                    if (less(a[j], a[min])) min = j;
                }
                exch(a, min, i);
            }
        }

        private static void exch(IComparable[] a, int i, int j)
        {
            IComparable temp = a[i];
            a[i] = a[j];
            a[j] = temp;
        }

        private static bool less(IComparable v, IComparable w)
        {
            return v.CompareTo(w) < 0;
        }
        private static void show(IComparable[] a)
        {
            //打印数据
        }
        private static bool isSorted(IComparable[] a)
        {
            for (int i = 1; i < a.Length; i++)
            {
                if (less(a[i], a[i - 1])) return false;
            }
            return true;
        }
    }

这里遵循我们约定的规则设计了Selection算法类,运行后,发现可以获得正确的排序结果。

分别执行大小为100,1000,10000,100000的数组后发现,选择排序在大规模排序时使用耗费的时间相当长,中小规模排序可以满足基本使用。

插入排序

概述:

如同日常整理纸牌一样,将每个元素插入到已有序的序列中适当位置,为了给插入的元素腾出空间,我们需要将其余所有元素在插入之前都右移一位。这种算法,我们称为插入排序。

分析:

和选择排序不同,插入排序的所需时间完全取决于输入中元素的初始位置。例如,对一个很大的有序数组进行排序将会比对随机顺序的数组或者逆序数组进行排序要快得多。

对于随机排列的长度为N且主键不重复的数组,平均情况下插入排序需要~(N^2)/4次比较及~(N^2)/4次交换。最坏情况下需要~(N^2)/2次比较及~(N^2)/2次交换,最好情况下需要N-1次比较和0次交换。

实现:

public class Insertion
    {
        public static void sort(IComparable[] a)
        {
            //排序代码
            int N = a.Length;
            for (int i = 1; i < N; i++)
            {
                for (int j = i; j > 0 && less(a[j], a[j - 1]); j--)
                    exch(a, j, j - 1);
            }

        }
        //优化交换次数
        public static void fasterSort(IComparable[] a)
        {
            int N = a.Length;
            for (int i = 1; i < N; i++)
            {
                IComparable temp = a[i];
                int j = i - 1;
                while (j > 0 && less(temp, a[j]))
                {
                    a[j + 1] = a[j];
                    j--;
                }
                a[j + 1] = temp;
            }
        }
        private static void exch(IComparable[] a, int i, int j)
        {
            IComparable temp = a[i];
            a[i] = a[j];
            a[j] = temp;
        }

        private static bool less(IComparable v, IComparable w)
        {
            return v.CompareTo(w) < 0;
        }
        private static void show(IComparable[] a)
        {
            //打印数据
            for (int i = 1; i < a.Length; i++)
            {
                Console.WriteLine(a[i]);
            }
        }
        private static bool isSorted(IComparable[] a)
        {
            for (int i = 1; i < a.Length; i++)
            {
                if (less(a[i], a[i - 1])) return false;
            }
            return true;
        }
}

通过多次实验输入,发现插入排序在处理大规模数据时也相当慢。但是和选择排序不同,当输入为较大大规模有序数据(如大小100000时),速度要快的多,而选择排序则依旧需要漫长的排序时间,这点是优于选择排序的。

时间: 2024-08-21 13:46:12

算法手记(5)初级排序算法的相关文章

深入理解排序算法(一):初级排序算法

[本系列博文会对常见的排序算法进行分析与总结,并会在最后提供几道相关的一线互联网企业面试/笔试题来巩固所学及帮助我们查漏补缺.项目地址:https://github.com/absfree/Algo.由于个人水平有限,叙述中难免存在不清晰准确的地方,希望大家可以指正,谢谢大家:)] 一.概述 我们在日常开发中经常需要对一组数据对象进行排序,这里的数据对象不仅包括数字,还可能是字符串等抽象数据类型(Abstract Data Type).由于排序是很多其他操作(比如二分查找)能够高效进行的基础,因

[读书笔记]算法(Sedgewick著)·第二章.初级排序算法

本章开始学习排序算法 1.初级排序算法 先从选择排序和插入排序这两个简单的算法开始学习排序算法.选择排序就是依次找到当前数组中最小的元素,将其和第一个元素交换位置,直到整个数组有序. 1 public static void sort(Comparable a[]){ 2 int N = a.length; 3 for(int i = 0; i < N; i ++){ 4 int min = i; //最小元素索引 5 for(int j = i + 1; j < N; j++){ 6 if(

初级排序算法1-定义排序规则

初级排序算法-定义排序规则 排序就是将一组对象按照某种逻辑序列重新排列的过程. Table of contents 介绍 为什么学它 排序算法类的模板 验证 性能评估 介绍 现在计算机的广泛使用使得数据无处不在,而整理数据的第一步通常就是进行排序 所有的计算机都实现了各种排序算法以供系统和用户使用 为什么学它 即使你只是使用标准库中的排序算法,学习排序算法仍然有三大实际意义 对排序算法的分析将有助于你全面理解比较算法性能的方法 类似的技术也能有效解决其他类型的问题 排序算法常常是我们使用算法解决

初级排序算法之选择排序

初级排序算法 本质是对要排序的数组进行嵌套循环,内层循环负责局部的排序,外层循环负责剩余的无序元素的递减.所以你只要理解嵌套循环和比较大小就能很快的掌握初级排序算法. 选择排序 一个无序的数组 a = [0, 4, 6, 3, 8, 2, 3, 9], 你也可以把a的元素想象成任何现实中可比较的具体物体.例如,有10根长短不一的木条,我们如何对它们进行排序?一个最直接的思想,先拿出最短的放到最前面,在剩余的木条中再拿出最短的放在第二位...直到最后一根木条.从中我们可以看出,1. 我们需要再一次

基本算法研究1-冒泡排序算法测试

基本算法研究1-冒泡排序算法测试 1.经典冒泡排序法基本原理 先看一个动态图,感觉比较形象: 冒泡排序(Bubble Sort)是一种简单的排序算法.默认是从小到大排序,即把最大的数据排在最后,相当于每次把最大数据像气泡一样浮到水面一样.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换. 基本步骤: 1.比较相邻的元素.如果第一个比第二个大,就交换他们两个.        2.对每一对相邻元素作同样的工作,从开始第一对

【JavaScript】【算法】JavaScript版排序算法

JavaScript版排序算法:冒泡排序.快速排序.插入排序.希尔排序(小数据时,希尔排序会比快排快哦) 1 //排序算法 2 window.onload = function(){ 3 var array = [0,1,2,44,4, 4 324,5,65,6,6, 5 34,4,5,6,2, 6 43,5,6,62,43, 7 5,1,4,51,56, 8 76,7,7,2,1, 9 45,4,6,7,8]; 10 //var array = [4,2,5,1,0,3]; 11 array

链表插入和删除,判断链表是否为空,求链表长度算法的,链表排序算法演示——C语言描述

关于数据结构等的学习,以及学习算法的感想感悟,听了郝斌老师的数据结构课程,其中他也提到了学习数据结构的或者算法的一些个人见解,我觉的很好,对我的帮助也是很大,算法本就是令人头疼的问题,因为自己并没有学习过算法的系统性的课程,现在还是处于不断摸索的阶段,好多算法题目根本就没有什么思路,导致自己对好多题目都很是头疼,就算是自己做过的一些算法的题目,再次遇到也还是不一定会做出来,他给出的建议就是,看懂别人的程序,然后自己去敲,一定会出错,然后调试,有错误接着调试,一直到没有错误为止,并且要时常的去复习

算法导论专题一--排序算法

排序算法作为许多程序的中间步骤,是计算机科学中的一个基本操作. 一.问题描述 排序算法输入的是n个数的一个序列<a1,a2…..an>,输出为输入的一个排列<a1’,…..an’>,满足a1’<a2’<….<an’ 简言之就是输入一个序列,输出的是这个数组元素从小到大排列的另一序列. 二.方法思想综述 从算法导论这本书上根据算法的复杂度可以将排序算法分为三种,,.,这两种方法都需要数据间的比较,而不需要. 其中有三种为选择,冒泡,插入. 选择排序:最直观,简单但是

算法导论专题一--排序算法(2)

上节分析了O(n^2)的算法,这节就分析O(nlgn)的算法-归并,快速和堆排序. 一:综述 O(nlgn) 的算法可以分为两大类,两者所用的技术差别较大.归并和快速排序采用的是分治策略,这两者相当于一个对称的过程,一个是自顶向上合并子问题,另一个则自上向下分解子问题.而堆排序利用堆这一数据结构元素间的特殊关系来排序一个序列,另外采用二叉树的方式组织数据使其效率大大提高. 二:分治策略排序算法 1.为什么使用分治? 在上节算法的分析中,不管是冒泡.选择还是插入都不适用于大规模的数据,因为数据一大