数据结构(Java)——查找和排序(4)

流年静坐,岁月冷暖,岁月匆匆,人生几何。
同时给大家推荐这个动态图文讲解8大排序算法写的非常赞!

1. 基数排序

前言:基数排序是基于队列处理的。
排序要基于某个特定值,我们将这个值成为排序关键字。基数排序并不是基于排序关键字来比较排序项,而是基于排序关键字的结构。对于排序关键字中的每个数字/字符的每种可能取值,都会创建一个单独的队列。队列的数目(或可能取值的种数)就称为基数(Radix)。
基数排序的概念是适用于任何类型的数据,只要是他们的排序关键字可以且分为一些固定位置。

1.1基数排序策略

·基数排序(以整型为例),将整型10进制按每位拆分,然后从低位到高位依次比较各个位。主要分为两个过程:
(1)分配,先从个位开始,根据位值(0-9)分别放到0~9号桶中(比如53,个位为3,则放入3号桶中)
(2)收集,再将放置在0~9号桶中的数据按顺序放到数组中,重复(1)(2)过程,从个位到最高位(比如32位无符号整形最大数4294967296,最高位10位) 。
(3) 最后形成的数组就是最终的有序数组。

1.2 基数排序Java实现

package ds.java.ch09;

import java.util.LinkedList;
import java.util.Queue;

/**
 * @author LbZhang
 * @version 创建时间:2015年11月20日 上午9:12:10
 * @description 基数排序
 */
public class RadixSort {

    /**
     * Performs a radix sort on a set of numeric values.
     */
    public static void main(String[] args) {
        int[] list = { 43, 4568, 8765, 6543, 7865, 4532, 987, 3241, 6589,
                6622, 11 };

        String temp;
        Integer numObj;
        int digit, num;

        // 队列的声明
        Queue<Integer>[] digitQueues = (LinkedList<Integer>[]) (new LinkedList[10]);

        // 初始化10个队列
        for (int digitVal = 0; digitVal <= 9; digitVal++)
            digitQueues[digitVal] = (Queue<Integer>) (new LinkedList<Integer>());

        // sort the list 四位数 处理
        for (int position = 0; position <= 3; position++) {
            for (int scan = 0; scan < list.length; scan++) {
                temp = String.valueOf(list[scan]);// /转化为字符串
                //System.out.println(temp+"*"+temp.length());
                if(temp.length()>position){
                    digit = Character.digit(temp.charAt(temp.length()-1 - position), 10);//十进制
                }else{
                    digit = Character.digit('0', 10);//十进制
                }

                digitQueues[digit].add(new Integer(list[scan]));// 队列
            }

            // gather numbers back into list  
            //整理数据还原到列表中
            num = 0;
            for (int digitVal = 0; digitVal <= 9; digitVal++) {
                while (!(digitQueues[digitVal].isEmpty())) {
                    numObj = digitQueues[digitVal].remove();
                    list[num] = numObj.intValue();
                    num++;
                }
            }
        }

        // output the sorted list
        for (int scan = 0; scan < list.length; scan++)
            System.out.println(list[scan]);
    }

}

2. 希尔排序

希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。

2.1 算法步骤

1)选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
2)按增量序列个数k,对序列进行k 趟排序;
3)每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

2.2 算法实现

package ds.java.ch09;

/**
 * @author LbZhang
 * @version 创建时间:2015年11月20日 上午10:30:10
 * @description 希尔排序
 */
public class ShellSortO {

    public static void main(String[] args) {
        int[] data = new int[] { 5, 2, 8, 9, 1, 3, 4, 11, 15, 12, 36, 17, 28,
                24, 10, 32, 24, 12, 36 };
        System.out.println("未排序前");
        for (int i = 0; i < data.length; i++) {
            System.out.print(data[i] + " ");
        }
        System.out.println();
        // /begin
        long startTime = System.nanoTime();// 获取当前时间
        // /excute program
        ShellSort1(data);
        // /end
        long endTime = System.nanoTime();
        System.out.println("程序运行时间: " + (endTime - startTime) + "ns");
        System.out.println("排序后");
        for (int i = 0; i < data.length; i++)
            System.out.print(data[i] + " ");
    }

    //希尔排序算法1
    public static void ShellSort1(int a[]) {
        int i, j, gap;
        int n = a.length;

        for (gap = n / 2; gap > 0; gap /= 2)
            // 步长定义步长 定长步长的设计插入排序
            for (i = 0; i < gap; i++) // 对同一分组的数据进行直接插入排序
            {
                for (j = i + gap; j < n; j += gap)
                    ///如果第j个元素比前面的元素小 那么执行插入算法
                    if (a[j] < a[j - gap]) {
                        int temp = a[j];//备份当前的数据
                        int k = j - gap;
                        ///统一后移
                        while (k >= 0 && a[k] > temp) {
                            a[k + gap] = a[k];
                            k -= gap;
                        }
                        a[k + gap] = temp;
                    }
            }
    }
}

3. 堆排序

堆排序的含义: 堆排序是利用堆的性质进行的一种选择排序。一句话是不断的将大(小)根堆中的最大值和最小值取出和最后的无序元素进行置换,然后调整无序部分,不断的重复这一过程,直到全部结束为止。

3.1 堆

堆实际上是一棵完全二叉树,其任何一非叶节点满足性质:
Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]或
即任何一非叶节点的关键字不大于或者不小于其左右孩子节点的关键字。 堆分为大顶堆和小顶堆,
满足Key[i]>=Key[2i+1]&&key>=key[2i+2]称为大顶堆,
满足 Key[i]=key[2i+1]&&Key[i]<=key[2i+2]称为小顶堆。

3.2 堆排序的思想

利用大顶堆(小顶堆)堆顶记录的是最大关键字(最小关键字)这一特性,使得每次从无序中选择最大记录(最小记录)变得简单。
1)将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
2)将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];
3)由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

3.3 堆排序的思想

package ds.java.ch09;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

/**
 * @author LbZhang
 * @version 创建时间:2015年11月20日 上午11:18:52
 * @description 类说明
 */
public class HeapSortTextBook {

    public static int[] Data = new int[10];

    public static void main(String[] args) {
        int i;// /循环变量
        int index;// /数组下标变量

        System.out.println("pls enter the value you want to sort: exit(0)");
        index = 1;// //读取输入数据存储到数组中

        InputStreamReader isr = new InputStreamReader(System.in);
        // /定义输入流
        BufferedReader br = new BufferedReader(isr);
        StringTokenizer st;
        // /输入数据构造数组
        do {
            System.out.print("Data " + index + ": ");
            try {
                String myline = br.readLine();
                st = new StringTokenizer(myline);
                Data[index] = Integer.parseInt(st.nextToken());

            } catch (IOException ioe) {
                System.out.println("IOError" + ioe);
            }
            index++;

        } while (Data[index - 1] != 0);
        System.out.print("排序前的内容:");
        for (i = 1; i < index - 1; i++) {
            System.out.print(" " + Data[i] + " ");
        }
        System.out.println();
        long startTime = System.nanoTime();// 获取当前时间

        // /因为最后一个Data[index-1]=0是一个终止的标志位 所以我们仅仅对1~index-2进行堆排序
        // /有效排序的数据是从1~index-2

        MyHeapSort(index - 2);

        System.out.print("堆排序后的效果: ");
        for (i = 1; i < index - 1; i++) {
            System.out.print(" " + Data[i] + " ");
        }
        System.out.println();

        long endTime = System.nanoTime();
        System.out.println("程序运行时间: " + (endTime - startTime) + "ns");
    }

    // ================
    // 建立堆
    // ================
    public static void CreateHeap(int root, int index) {

        // 创建
        int i, j;// /循环变量
        int temp;// /临时存储变量
        int finish;// /判断是否完成
        j = 2 * root;// /子节点的index
        temp = Data[root];// /暂存堆的root值
        finish = 0;// /预设堆尚未完成
        while (j <= index && finish == 0) {
            if (j < index) { // /找到最大子节点 这一步如果index%2==0 这一步就不需要走了
                if (Data[j] < Data[j + 1]) {
                    j++;
                }
            }
            if (temp >= Data[j]) { // 构建最大堆
                finish = 1;
            } else {
                Data[j / 2] = Data[j];// /父节点=目前结点 先调整当前的根节点和子节点的数据
                j = 2 * j; // 两个目的:首先是看是否完成了当前堆的构建;另一个是为了结束循环
            }
        }
        Data[j / 2] = temp;
    }

    /**
     * 堆排序程序
     * @param index
     */
    public static void MyHeapSort(int index) {

        int i, j, temp;
        //将二叉树转化为堆
        for (i = (index / 2); i >= 1; i--) {
            CreateHeap(i, index);
        }
        ////输出一下大根堆
        System.out.print("排序前的输出");
        for (i = 1; i <= index; i++) {
            System.out.print(" " + Data[i] + " ");
        }
        System.out.println();
        System.out.println(index);
        // //获取堆的root值放在最后一个无序结点上面
        // //循环 重复执行这一个过程最终实现堆排序完成

        for (i = (index - 1); i >= 1; i--) {
            temp = Data[i + 1];
            Data[i + 1] = Data[1];
            Data[1] = temp;
            CreateHeap(1, i);
        }

        System.out.print("Sort Processing:");
        for (j = 1; j <= index; j++) {
            System.out.print("**" + Data[j] + " ");
        }
        System.out.println();

    }

}