算法笔记:元素排序

排序在算法中是十分重要的问题,本节主要讲解最基本的排序算法,包括选择排序插入排序希尔排序,最后会讲解一个排序的实际应用。

一. 选择排序(Selection Sort)

public class Selection
{
 public static void sort(Comparable[] a)
 {
 int N = a.length;
 for (int i = 0; i < N; i++)
 {
 int min = i;
 for (int j = i+1; j < N; j++)
 if (less(a[j], a[min]))
 min = j;
 exch(a, i, min);
 }
 }
 private static boolean less(Comparable v, Comparable w)
 { /* as before */ }
 private static void exch(Comparable[] a, int i, int j)
 { /* as before */ }
}

选择排序,顾名思义,就是从左到右不断扫描数组,每次选择目标元素,把它提到前面。经过k次选择,前k项就是有序的,十分简单。

选择排序,并不是效率很高的排序。

二. 插入排序(Insertion Sort)

插入排序,同样可以顾名思义,就是把看到的元素提前,放到它应该放到的位置上去。

public class Insertion
{
 public static void sort(Comparable[] a)
 {
 int N = a.length;
 for (int i = 0; i < N; i++)
 for (int j = i; j > 0; j--)
 if (less(a[j], a[j-1]))
 exch(a, j, j-1);
 else break;
 }
 private static boolean less(Comparable v, Comparable w)
 { /* as before */ }
 private static void exch(Comparable[] a, int i, int j)
 { /* as before */ }
}

插入排序对于基本有序的数组,具有很高的效率。

三. 希尔排序(Shell Sort)

希尔排序是一种十分重要的排序算法。它产生时间很早(1959年),是最早突破上述排序算法的算法时间复杂度(O(n^2))的算法,它一方面十分简单,数行代码就可以实现,一方面这个算法的细节却依然有讨论和争议(分组大小)。这说明我们目前存在的问题,哪怕十分简单,依然有很大的改进空间,依然有很多精巧的算法等待我们发现。

public class Shell
{
 public static void sort(Comparable[] a)
 {
 int N = a.length;
 int h = 1;
 while (h < N/3) h = 3*h + 1; // 1, 4, 13, 40, 121, 364, ...
 while (h >= 1)
 { // h-sort the array.
 for (int i = h; i < N; i++)
 {
 for (int j = i; j >= h && less(a[j], a[j-h]); j -= h)
 exch(a, j, j-h);
 }

 h = h/3;
 }
 }
 private static boolean less(Comparable v, Comparable w)
 { /* as before */ }
 private static void exch(Comparable[] a, int i, int j)
 { /* as before */ }
}

算法思路:我们知道,插入排序对于基本有序的数组具有很高的效率,那么,我们能不能让数组从小到大,逐步变得有序呢?希尔排序采用的方法是先对数组进行分组,比如选择分组大小为3,则0,3,6,9,...,3n是一组,在组内使用插入排序,之后不断缩小分组大小,直到分组大小为1,就完成了排序。

希尔排序的算法复杂度比较难分析,总之小于O(n^2)。

四. 凸包寻找问题

关于凸包寻找问题(Convex Hull),在Graham扫描法找凸包(convexHull)中有比较详尽的描述,在此只是简要介绍一下思路方法。

上图显示了我们要处理的问题和使用的基本思路。

问题

在二维平面中给定一组点,我们希望找到最少的点,把所有点包裹进来。

基本思路

首先,我们选定最底下的点1,作为起始点,之后计算所有点以1为极坐标远点的θ值,把θ值从小到大排序,得到一组点的排列{1,2,3,4,5,6,7,8,9,10,11,12}。

可以确定0,1两点一定会被选中,之后把2加入点集,但是当3要加入点集的时候,我们发现似乎2不在点集中,因为从基点开始,凸包上每条相临的线段的旋转方向应该一致。如果发现新加的点使得新线段与上线段的旋转方向发生变化,则可判定上一点必然不在凸包上。实现时可用向量叉积进行判断,设新加入的点为 pn+1pn+1,上一点为 pnpn,再上一点为 pn−1pn−1。顺时针扫描时,如果向量 <pn−1,pn><pn−1,pn> 与 <pn,pn+1><pn,pn+1> 的叉积为正,则将上一点删除。

我们需要用回溯法来解决这个问题。

算法

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值