排序算法代码总结

来源:互联网 发布:地学软件 编辑:程序博客网 时间:2024/05/16 09:15

原博客网址http://blog.csdn.net/roamer_nuptgczx/article/details/51524466

目录

    • 前言
    • 冒泡排序
    • 选择排序
    • 插入排序
    • 快速排序
    • 归并排序
    • 堆排序
    • 希尔排序
    • 基数排序
    • 参考资料


前言

排序算法在笔试面试中几乎是必考的,因为它是很多复杂算法的基础,也是我们学习数据结构与算法的入门知识。目前网上介绍各类排序算法的博客和帖子非常多,但其中有不少作者提供的代码有错误或者代码中没有考虑特殊情况。在此,我们再次总结一下常见的八大排序算法,试图讲清楚各个算法的基本原理,并提供Java代码以及详细的注释。所有代码都是对数组进行升序排列且已经测试通过,但没有使用足够的测试用例,如果代码中存在问题,请大家留言指出,或者有更好的算法思路,也可以交流讨论。


冒泡排序

/** * 冒泡排序 *  * 原理: * 每一轮循环中依次比较相邻位置上元素的大小,使得较大的元素后移, * 且确保第i轮循环完之后能把第i大的元素移动到排序后的位置上 *  * 改进: * 每一轮循环开始前设置标志位,如果本轮循环没有交换任何元素, * 则说明所有元素已经有序,可以提前结束排序 *  * @author Roamer */void bubbleSort(int[] a) {    if(a == null || a.length == 0) return;    boolean flag;    for(int i = a.length - 1; i > 0; --i) {        flag = true;//每一轮冒泡之前重置标志位        for(int j = 0; j < i; ++j) {            if(a[j] > a[j+1]) {                swap(a, j, j+1);                flag = false;            }        }        if(flag) break;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

选择排序

/** * 选择排序 *  * 原理: * 从数组的首元素开始,将第i个元素之后的所有元素通过相互比较找到最小值的索引, * 如果当前元素比这个最小元素大,则交换之,使得第i个位置的元素值为第i小, * 相当于每一轮循环是在所有未排序的元素之中选择出最小的元素。 *  * @author Roamer */void selectSort(int[] a) {    if(a == null || a.length == 0) return;    for(int i = 0; i < a.length - 1; ++i) {        //找到第i个元素之后的最小元素的下标minIdx        int minIdx = i + 1;        for(int j = i + 2; j < a.length; ++j) {            if(a[j] < a[minIdx])                minIdx = j;        }        //如果当前元素比其后的最小元素还小,则交换之        if(a[i] > a[minIdx])            swap(a, i, minIdx);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

插入排序

/** * 插入排序 *  * 原理: * 确保数组前i-1个元素已经排好序,在第i轮循环时,将第i个元素从后往前依次和 * 其前面的元素比较和交换,最后插入到前i-1个有序的子数组中的合适位置 *  * @author Roamer */void insertSort(int[] a) {    if(a == null || a.length == 0) return;    //从数组第二个元素开始进行前插    for(int i = 1; i < a.length; ++i) {        for(int j = i; j > 0 && a[j-1] > a[j]; --j)                swap(a, j-1, j);    }}/** * 插入排序改进 *  * 如果当前元素已经位于正确的位置,则不必继续往前插入,可以提前结束本轮循环 *  * @author liwendongyang */void insertSort2(int[] a) {    if (a == null || a.length == 0)        return;    // 从数组第二个元素开始进行前插    for (int i = 1; i < a.length; ++i) {        for (int j = i; j > 0; --j) {            if (a[j - 1] > a[j])                swap(a, j - 1, j);            else                break;        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

快速排序

/** * 快速排序 *  * 原理: * 将数组的首元素作为比较的基准,用两个指针从数组的两端往中间扫描, * 当左指针对应的元素大于基准值且右指针对应的元素小于基准值,则交换两者对应的元素值, * 使得每一轮遍历之后数组分成比基准值更大和更小的两部分, * 再把基准元素从数组首位交换到数组的中间,从而其左边的元素都不大于它, * 且其右边的元素都不小于它,然后将左右两个子数组递归调用快排函数,最终使数组有序 *  * @author Roamer */void quickSort(int[] a, int low, int high) {    if(a == null || a.length == 0) return;    if(low < high){          int pivot = partition(a, low, high);        quickSort(a, low, pivot - 1);          quickSort(a, pivot + 1, high);    }}//版本一:两个指针互相交换不合格元素(交换之后就都合格了),最后将基准元素移动到中间private int partition(int[] a, int low, int high) {    //将数组首元素作为每一轮比较的基准    int pivot = low;    while(low < high) {        //从右往左扫描,直到遇到比基准元素小的元素        while(low < high && a[high] >= a[pivot])            --high;        //从左往右扫描,直到遇到比基准元素大的元素        while(low < high && a[low] <= a[pivot])            ++low;        //将左子数组中不合格的元素与右子数组中不合格的元素交换        swap(a, low, high);     }    //将数组首元素交换到中间位置    swap(a, pivot, low);    //返回数组的中轴位置    return low;}//版本一的改进版://由于基准元素已经保存了,所以其位置可以被覆盖掉,且两个指针是交替扫描的,//所以右边(左边)的不合格元素可以直接覆盖左边(右边)的不合格元素,//由于high指针先扫描,然后两个指针的元素交替覆盖对方,所以循环结束后,//low对应的位置还没有被覆盖,且它就是两个子数组的分界,将基准元素放到此位置即可private int partition1(int[] a, int low, int high) {    //将数组首元素作为每一轮比较的基准    int pivotValue = a[low];    while(low < high) {        //从右往左扫描,直到遇到比基准元素小的元素        while(low < high && a[high] >= pivotValue)            --high;        //将右子数组中不合格的元素放到左边不合格元素的位置(原元素已经移走)        a[low] = a[high];        //从左往右扫描,直到遇到比基准元素大的元素        while(low < high && a[low] <= pivotValue)            ++low;        //将左子数组中不合格的元素放到左边不合格元素的位置(原元素已经移走)         a[high] = a[low];    }    //将基准元素放到中间位置    a[low] = pivotValue;    //返回数组的中轴位置    return low;}//版本二:保持两个指针中总有一个指向基准元素,所以每次交换都是不合格元素与基准元素做交换,//当两个指针在数组中间相遇时,low一定指向着基准元素private int partition2(int[] a, int low, int high) {    //将数组首元素作为每一轮比较的基准    int pivotValue = a[low];    while(low < high) {        //从右往左扫描,直到遇到比基准元素小的元素        while(low < high && a[high] >= pivotValue)            --high;        //将右子数组中不合格的元素与基准元素交换        swap(a, low, high);        //从左往右扫描,直到遇到比基准元素大的元素        while(low < high && a[low] <= pivotValue)            ++low;        //将左子数组中不合格的元素与基准元素交换        swap(a, low, high);     }    //返回数组的中轴位置,low必定指向了基准元素pivotValue    return low;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106

归并排序

/** * 归并排序(递归版) *  * 原理: * 将数组均分成两个子数组,先将两个子数组分别进行排序,然后合并得到全体元素都有序的数组, * 为使上述的两个子数组分别有序,需要先对其各自的两个子数组进行排序再合并,因此需要递归地 * 对每个子数组的两个子数组进行归并排序,直到子数组只有2个元素,此时只需要直接进行合并 *  * @author Roamer */void MergeSort(int[] a) {    if(a == null || a.length == 0) return;    int[] b = new int[a.length];//辅助数组    Merge(a, b, 0, a.length-1, (a.length-1)/2);}//对数组a的两个子数组进行归并排序private void Merge(int[] a, int[] b, int low, int high, int pivot) {    //先递归地划分子数组(子数组最小长度为2),并对子数组进行归并排序    if(low < high) {        Merge(a, b, low, pivot, (low+pivot)/2);        Merge(a, b, pivot+1, high, (high+pivot+1)/2);    }    //将已经排好序的两个子数组元素依次进行比较再合并    int i = low;    int j = pivot+1;    int k = low;    while(i <= pivot && j <= high){        if(a[i] < a[j])            b[k++] = a[i++];        else            b[k++] = a[j++];    }    //取出子数组中可能的剩余元素(每次只可能有一个while执行)    while(i <= pivot)  b[k++] = a[i++];    while(j <= high)  b[k++] = a[j++];      //将本次排好序的部分元素拷贝回原数组a    System.arraycopy(b, low, a, low, high-low+1);}/** * 归并排序(迭代版) *  * 原理: * 先将整个数组依次划分成若干个长度为2的子数组,对每个子数组中的两个元素进行合并, * 再将整个数组依次划分成若干个长度为4的子数组,对每个子数组中的两个子数组进行合并, * 如此循环,直到只能将数组划分成两个子数组,这两个子数组已经分别有序,直接合并即可 *  * @author Roamer *///利用分治策略,对数组a的各级子数组进行迭代归并void MergeSort2(int[] a) {    if(a == null || a.length == 0) return;    int[] b = new int[a.length];//辅助数组    int len = 2;//每一轮合并中数组的长度    while(len <= a.length) {        //将前若干组中两个等长的子数组合并        int i = 0;        while(i + len <= a.length) {            Merge2(a, b, i, i+len-1, i+(len-1)/2);            i += len;        }        //若原数组长度不是2的幂,则数组可能不能被均分        //从而最后一组的两个子数组长度会不同,单独合并之        if(i != a.length)            Merge2(a, b, i, a.length-1, (i+a.length)/2);        //下一轮合并中数组的长度翻倍        len <<= 1;        //将本轮分组有序的元素拷贝回原数组a        System.arraycopy(b, 0, a, 0, a.length);    }    //若原数组长度不是2的幂,需要最后合并一次!    if(len != a.length) {        Merge2(a, b, 0, a.length-1, (len-1)/2);        System.arraycopy(b, 0, a, 0, a.length);    }}private void Merge2(int[] a, int[] b, int low, int high, int pivot) {    //将已经排好序的两个子数组元素依次进行比较再合并    int i = low;    int j = pivot+1;    int k = low;    while(i <= pivot && j <= high){        if(a[i] < a[j])            b[k++] = a[i++];        else            b[k++] = a[j++];    }    //取出子数组中可能的剩余元素(每次只可能有一个while执行)    while(i <= pivot)  b[k++] = a[i++];    while(j <= high)  b[k++] = a[j++];}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105

堆排序

/** * 堆排序 *  * 原理: * 先将无序数组构成一个二叉堆(完全二叉树),使得每个节点都小于其子节点(兄弟节点之间可以无序), * 每次取出根节点后,重新调整堆使其仍满足上述特性,每次取出的根节点就构成了一个有序数组。 *  * 建堆 * 用数组来存放整个二叉堆,且数组的首元素中存储着整个二叉堆的节点总个数, * 建堆时总是在二叉堆的叶子节点处插入新节点,然后“上浮”该节点,最终在数组中得到一个二叉堆。 *  * 调整堆 * 每次在叶子节点处插入新节点即在数组末位插入新元素需要调整堆,比较新节点和其父节点的大小, * 通过不断交换使其“上浮”,并最终位于二叉树的合适位置; * 每次取出二叉堆的根节点即取出数组的第二个元素后需要调整堆,将二叉树的最后一个叶子节点作为新的根节点, * 然后依次比较其和子节点的大小,通过不断交换使其“下沉”,并最终位于二叉树的合适位置; *  * @author Roamer */void heapSort(int[] a) {    int[] b = new int[a.length + 1];//二叉堆数组    //建堆    for(int i = 0; i < a.length; ++i)        insert(b, a[i]);    //得到有序数组    for(int i = 0; i < a.length; ++i)        a[i] = getRoot(b);}//往二叉堆插入新节点,并调整堆private void insert(int[] heap, int ele) {    heap[0] += 1;//节点总数加1    heap[heap[0]] = ele;    goUp(heap);}//取出二叉堆的根节点,并调整堆private int getRoot(int[] heap) {    if (heap[0] < 1)         throw new RuntimeException("二叉堆已经为空,不能再取出元素!");    int root = heap[1];//取出根节点元素    heap[1] = heap[heap[0]];//将二叉堆的最后一个叶子节点作为新的根节点    heap[0] -= 1;//节点总数减1    goDown(heap);    return root;}//根节点"下沉"private void goDown(int[] heap) {    int idx = 1;//需要下沉的根节点的索引    int left, right, minIdx;//minIdx表示左右子节点中较小的那个    boolean flag = true;//是否有元素交换的标志位    //如果上一轮循环有元素交换则继续交换    while(flag) {        flag = false;        left = (idx << 1);//左子节点        right = left + 1;//右子节点        if (left > heap[0])//无子节点            break;         else if (right > heap[0])//只有左子节点            minIdx = left;        else            minIdx = (heap[left] < heap[right]) ? left : right;        if (heap[idx] > heap[minIdx]) {            swap(heap, idx, minIdx);            idx = minIdx;            flag = true;//本次循环有元素交换        }    } }//末位叶子节点“上浮”private void goUp(int[] heap) {    int idx = heap[0];    int parent = (idx >> 1);    while(parent > 0 && heap[idx] < heap[parent]) {        swap(heap, idx, parent);        idx  = parent;        parent = (idx >> 1);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92

希尔排序

/** * 希尔排序(缩小增量排序) *  * 原理: * 先设置一个较大的步长(增量),将数组分为若干个子序列,对每个子序列分别进行排序, * 再减少步长,再次将数组分为若干个更长的子序列,对每个子序列分别进行排序, * 如此循环,直到步长为1,即整个数组中只有一个子序列,此时整个数组已经有序 * 其中,子序列的排序可以采用任何其他排序算法,每一轮排序之后,数组将变得更加有序一些 *  * @author Roamer */void shellSort(int[] a) {    //得到初始步长    int step = 1;    while(step < a.length)         step = 3*step + 1;    while(step > 1) {        //缩小步长        step = step / 3 + 1;        for (int i = 0; i < step; ++i) {            // 得到子序列数组            int nsub = (a.length - i - 1) / step + 1;            int[] sub = new int[nsub];            for (int j = 0; j < nsub; ++j)                sub[j] = a[i + j * step];            //对子序列数组进行冒泡排序            bubbleSort(sub);            //将排序后的元素保存到原数组的对应位置            for (int j = 0; j < nsub; j++)                a[i + j * step] = sub[j];        }       }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

基数排序

/** * 基数排序 *  * 原理: * 基数排数基于桶排序的思想。如果需要排序的元素是正整数,则可以通过依次比较他们每个数位上 * 数字的大小进行排序,由于十进制只有10个数码,所以只需要10个“桶”就够了。 * 基数排序的方式可以采用LSD(Least sgnificant digital)或MSD(Most sgnificant digital), * 如果是采用LSD算法,则从个位开始,将所有整数根据个位数字分别放到对应的10个桶中, * 再按顺序从各个桶中将所有整数取出依次填回原数组,然后将所有整数根据十位数字重新放到新的10个桶中, * 以此类推,直到所有元素的所有数位都遍历完,由于基数排序是稳定的,所以数组中的所有元素最终都有序了 *  * @author Roamer */void radixSort(int[] a, int len) {    int k = 0;//用于遍历数组的下标指针    int m = 1;//表示当前用于比较的数位,从个位开始    int n = 1;//表示数位m对应的权重,即1,10,100,1000...    //数组的第一维为每个数位上可能出现的数字(0~9),即桶的个数,    //第二维是包含当前数位的元素可能的总个数,即每个桶中可以放入的整数个数,    //数组的元素值记录了数位是lsd的整数    int[][] bucket = new int[10][a.length];    int[] order = new int[10];//用于记录每个桶中整数的总个数     while(m <= len) {        //入桶,即将数组中的所有整数按照数位m放到对应的桶中        for(int i = 0; i < a.length; ++i) {                 int lsd = (a[i] / n) % 10;//通过取整取余得到数位m上的数字lsd            bucket[lsd][order[lsd]] = a[i];//记录新出现的数位是lsd的整数            order[lsd]++;//数位是lsd的整数的个数加1        }        //出桶,即从10个桶中依次取出整数,填回数组中(即记录当前已排好的相对顺序)        for(int i = 0; i < 10; i++) {            //如果当前桶不为空            if(order[i] != 0) {                //依次取出当前桶中的记录的整数(bucket数组第二维中元素必定是连续的)                for(int j = 0; j < order[i]; j++)                    a[k++] = bucket[i][j];                //清空对桶中整数个数的记录                 order[i] = 0;            }        }        //完成当前数位上的排序,准备下一轮排序        k = 0;//将数组a的下标重置为0        m++;//数位往高位增加        n *= 10;//数位对应的权重增加    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

参考资料

1: 纸上谈兵: 排序算法简介及其C实现

2: 面试中的排序算法总结

3: 基数排序——百度百科

原创粉丝点击