Algorithms - Sort

Graph内容过于复杂,而且近期面试不会很容易考到。
Graph系列链接:
http://www.jianshu.com/p/f968ef8dc0b6
所以先复习排序。
今天上午看了,
selection sort
insertion sort
insertion sort without exchanges
shell sort
merge sort

并且写了代码。之后会粘贴上。意义挺大。

                                                                      ---- Richardo 09/16/2015

下面先讲一个我对Java static 的新认识。
static 表示是,固有的特征。一个类如果有static变量或者方法。表示这个方法或者变量,是这个类的固有特征. 可以直接通过, Class.xxx 直接使用。因为这是我的固有特征,即使每个类的对象里面有些细节不同,但是这个特征,大家都是相同的。
就好像两个亲生兄弟,可能会有许多不同,但是他们的父亲一定是相同的。
A.father B.father
就是这么个意思。
但是,如果在方法里,再次申明了这个变量。那么,在这个方法中,这个static变量不会起作用,你申明等于多少,他就会等于多少。但等到函数结束,这个局部变量的效果也就结束了。

第二个认识。
我知道public static void func() { } 特点就是可以直接调用。
那么,private static void func() {} 意义何在呢?
在公共static方法中使用到的其他任何方法,任何变量。都必须是static的。
所以这是private static 意义所在。否则别人用这个公共方法,却不能使用里面的私有方法,程序就无法继续执行,就会出错。
但是,请注意,我们是需要考虑安全因素的。static只能保证使用权,而不能获得像公共方法一样的了解权。也就是说,我无法在其他类中,直接使用这个私有方法,而只能通过某个公共方法间接地去使用这个私有方法。因此,安全得到了保证。

                                                                  ---- 09/16/2015  12:19

selection sort
就是第一遍从第一个开始遍历到底,找出最小的,放在第一个。
第二遍从第二个开始遍历到底,找出最小的,放在第二个。
如此往复。
优势: exchange 次数很小,只有~N,据说是最小的。线性。
复杂度, ~O(N2 / 2)
但是感觉没什么用。。不具体讲了,代码如下。

public static void sort(Comparable[] a) {
        if (a == null || a.length == 0)
            return;
        for (int i = 0; i < a.length; i++) {
            int minIndex = i;
            for (int j = i + 1; j < a.length; j++) {
                if (a[j].compareTo(a[minIndex]) < 0)
                    minIndex = j;
            }
            Comparable temp = a[i];
            a[i] = a[minIndex];
            a[minIndex] = temp;
        }
    }

insertion sort
遍历前两个,比较i 与 i - 1,如果a[i] < a[i -1],则 swap(a[i], a[i - 1]);
and then compare a[i - 2] and a[i - 1]
类似于冒泡排序。把最小的往前冒泡。
优势:对已经排好序的数列,进行insertion sort, 速度很快,运行时间线性。
很重要的优势。如果以后别人给你一个大致排好序的数列,就可以考虑用插入排序而不是想都不想直接使用快速排序了。
复杂度 ~ O(N2 / 4)
代码如下:

public static void sort(Comparable[] a) {
        if (a == null || a.length == 0)
            return;
        for (int i = 1; i < a.length; i++) {
            for (int j = i; j >= 1; j--) {
                if (a[j - 1].compareTo(a[j]) > 0) {
                    Comparable temp = a[j];
                    a[j] = a[j - 1];
                    a[j - 1] = temp;                }
            }
        }
    }

Insertion sort without exchanges
之前的插入排序,一个很大的问题是,一旦发现某个值小于他前面的值,就要交换一下,需要三次取值操作,大大浪费了时间和资源。
于是开发出了一种方法只需要一次取值操作。
记录下,起点a[i]
temp = a[i];
int k = i - 1;
while (k >= 0 && a[k] < temp) {
a[k + 1] = a[k];
k--;
}
然后,当前面的值大于了他,或者到0的时候,再把它复原。
综上,插入排序在大规模测试中,速度还是要比选择排序更快的。
代码如下:

public static void sort(Comparable[] a) {
        if (a == null || a.length == 0)
            return;
        
        for (int i = 1; i < a.length; i++) {
            Comparable temp = a[i];
            int k = i - 1;
            while (k >= 0 && a[k].compareTo(temp) > 0) {
                a[k + 1] = a[k];
                k--;
            }
            a[k + 1] = temp;
        }
    }

shell sort
这是一种我之前没怎么印象,或者说,完全忘记了的算法。
下面讲一讲他的思路。
他是插入排序的改进版。
插入排序为什么慢?因为他的元素是一个个移动的。所以,他的特点是,到后期,越来越快。因为前面已经排列的差不多了。
那么,有办法,让他移动的格子更多些吗?前期加快移动的幅度,让他大致成型,然后,再来一次总的插入排序,因为之前已经大致成型了,所以最后一轮插入排序会很快。
这就是 shell sort 的思想。
于是,设置一个 k, k = 1, 4, 13, 53....
k = 3 * k + 1 and k < N
然后将数列分成k块。块与块之间进行排序。
比如,
k = 4
i = k;
9 8 7 6 5 4 3 2 1
a[0] compare with a[4], swap or not
5 8 7 6 9 4 3 2 1
a[4] compare with a[8], swap or not
5 8 7 6 1 4 3 2 9

i = k + 1 = 5;
a[1] compare with a[5], swap or not
5 4 7 6 1 8 3 2 9
a[5] compare with a[9], a[9] does not exist
quit

i = k + 2 = 6
a[2] compare with a[6], swap or not
5 4 3 6 1 8 7 2 9
a[6] compare with a[10], a[10] does not exist
quit

i = k + 3 = 7
a[3] compare with a[7], swap or not
5 4 3 2 1 8 7 6 9
...
quit

i = k + 4 = 8
a[4] compare with a[8], swap or not
not swap
5 4 3 2 1 8 7 6 9

k = 1;
i = k;
=> k = 1; i = 1;
就是插入排序了。
可以看到,
原输入队列是,
9 8 7 6 5 4 3 2 1

现在插入排序的输入队列是,
5 4 3 2 1 8 7 6 9

放在一块对比下,
9 8 7 6 5 4 3 2 1
5 4 3 2 1 8 7 6 9
可以看到,小的都往前面移动了很多,大的相对往后移动了很多。
于是,插入排序的效率会很高,效率会很快。

代码如下:

public static void sort(Comparable[] a) {
        if (a == null || a.length == 0)
            return;
        
        for (int i = 1; i < a.length; i++) {
            Comparable temp = a[i];
            int k = i - 1;
            while (k >= 0 && a[k].compareTo(temp) > 0) {
                a[k + 1] = a[k];
                k--;
            }
            a[k + 1] = temp;
        }
    }

下面是,普林斯顿算法书对shell sort的评价,感觉很客观。
**
We shall see methods that are more efficient, but they are perhaps only twice as fast (if that much) except for very large N, and they are more complicated. If you need a solution to a sorting problem, and are working in a situation where a system sort may not be available (for example, code destined for hardware or an embedded system), you can safely use shell sort, then determine sometime later whether it will be worthwhile to replace it with a more sophisticated method.
**

merge sort
merge sort 分为两种, top-down and bottom-up
我刚看到 top-down
介绍下。
其实大家也都熟悉了,就是分治的思想,分成一个个块,然后,再合体。
从顶上开始分。
分成两块,分别排序。
假设已经排好了。
然后新建一个数组,将两个子数组按照大小顺序合并在这个总数组上,再返回。
这就是top - down 的思想。
代码如下:

public class MergeSort {
    private static Comparable[] aux;
    public static void sort(Comparable[] a) {
        if (a == null || a.length == 0)
            return;
        
        aux = new Comparable[a.length];
        sort(a, 0, a.length - 1);
        int g = 15;
    }
    
    private static void sort(Comparable[] a, int lo, int hi) {
        if (lo >= hi)
            return;
        int mid = lo + (hi - lo) / 2;
        sort(a, lo, mid);
        sort(a, mid + 1, hi);
        merge(a, lo, mid, hi);
    }
    
    private static void merge(Comparable[] a, int lo, int mid, int hi) {
        for (int i = lo; i <= hi; i++)
            aux[i] = a[i];
        int i = lo;
        int j = mid + 1;
        for (int k = lo; k <= hi; k++) {
            if (j > hi)
                a[k] = aux[i++];
            else if (i > mid)
                a[k] = aux[j++];
            else if (aux[i].compareTo(a[j]) < 0)
                a[k] = aux[i++];
            else
                a[k] = aux[j++];
        }
    }
}

感觉merge这个函数写的很巧妙,老师写的。
为什么呢?
以前我处理merge的时候,也是循环,但是时while,然后条件是,
while(i < left.length && j < right.length) {
...
...
}
if (i == left.length)
{....}
else
{....}

很麻烦,然后这代码,直接把这些事都在一个循环里面做完了。可以自己体会下,很巧妙。

暂且更新到这里。最近很忙。刚收到通知,9.30,面试微软。很紧张也很兴奋。在浪潮之巅里面的看到的公司,当时觉得高不可攀,现在竟然有机会去参加他的面试。
虽然希望很渺茫,但我一定会去努力尝试的!!!

                                                             ------ Richardo 09/17/2015 21:19

quick sort 更新

My code:

import java.io.*;
import java.util.*;

public class Solution {  
   
   public static void sort(int[] nums) {
       if (nums == null || nums.length == 0)
           return;
       quicksort(0, nums.length - 1, nums);
   }
    
   private static void quicksort(int lo, int hi, int[] nums) {
       if (lo >= hi)
           return;
       int middle = lo + (hi - lo) / 2;
       int pivot = nums[middle];
       int i = lo;
       int j = hi;
       while (i <= j) {
           while (nums[i] < pivot)
               i++;
           while (nums[j] > pivot)
               j--;
           if (i <= j) {
               int temp = nums[i];
               nums[i] = nums[j];
               nums[j] = temp;
               i++;
               j--;
           }
       }
       if (lo < j)
           quicksort(lo, j, nums);
       if (i < hi)
           quicksort(i, hi, nums);
   }
    
    
   public static void main(String[] args) {  
       int[] nums = {5, 3, 4, 2, 6, 1};
       Solution.sort(nums);
       for (int i = 0; i < nums.length; i++)
           System.out.println(nums[i]);
   }  
 }  

明天是春季career fair,抓住机会。加油。

Anyway, Good luck, Richardo!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容