八大排序算法简明扼要

八大排序算法



冒泡排序(暴力排序)、选择排序、快速排序、归并排序(后序排序)、链式基数排序、插入排序、希尔排序、堆排序。
拥有相关性的排序:
(选择排序、快速排序);(插入排序、希尔排序);
 



时间复杂度和空间复杂度。
例子:for循环n次, for中执行的代码为单元。
时间复杂度:n循环的次数 O(n);
空间复杂度:此循环所占存储器上存储空间,复杂度:O(n)即 一个单元所占空间 * n  ; (如果for中单元为常量则空间是固定的,复杂度:O(1))

分治法:
顾名思义,分而治之。将一个大的整体拆分为若干个小元素。前提是,不管整体还是小元素,其执行流程应该不变。如二分查找,就是每次从中间开始分,直到找到最终元素,其比较的流程不变。



* 冒泡排序(暴力排序)
适用:适用于小数据,8个以内数据最快。短处:不适用与大量数据,资源消耗过多。时间复杂度和空间复杂度过多。
原理+步骤:
相邻数据进行比较,按大或小,进行交换,类似气泡,从头到尾逐渐排序。
1.相邻数据进行比较,按大或小,进行交换
2.然后指针指向下一位,重复步骤1,最后是最大或最小值排列在队尾部
3.去掉已排列的数据,重复1,2  最终所有数据都已完成排序为止

 /**
   * 冒泡排序,相邻数据比较,交换
   */
  public void bubbleSort(int[] array) {
    for (int i = 0; i < array.length; i++) {
      boolean flag = true;
      for (int j = 0; j < array.length - 1 - i; j++) {
        if (array[j] < array[j + 1]) {
          int x = array[j];
          array[j] = array[j + 1];
          array[j + 1] = x;

          flag = false;
        }
      }

      if (flag) {
        break;
      }
    }
  }

解读代码:冒泡排序有很多写法,都很简单。
这里flag的创建,为了减少排列的次数。因为每次排序都是从0到array.length-1-i 开始 ,当没有交换发生时,说明已经完全排序好了,那么如果外层循环有剩余,就直接退出,不再进行比较排序了。


* 选择排序
适用:适用于小数据,8个以内数据最快。采用遍历数组,找到最小或最大数据的下标,然后交换。短处:不适用于大数据
原理+步骤:
采用遍历数组,找到最小或最大数据的下标,然后交换。
1.采用遍历数组,找到最小或最大数据的下标
2.记录初始位置下标,然后交换。
3.初始下标++,重复1,2。直至完成排序。

/**
   * 选择排序
   */
  public void selectSort(int[] array) {

    int index;
    int target;
    for (int i = 0; i < array.length; i++) {
      index = i;
      for (int j = i + 1; j < array.length; j++) {
        if (array[j] < array[index]) {
          index = j;
        }
      }

      if (index != i) {
        target = array[index];
        array[index] = array[i];
        array[i] = target;
      }
    }

//    int index ;
//    int j;
//
//    int target;
//    for (int i = 0; i < array.length; i++) {
//      target = array[i];
//      index = i;
//      j = i+1;
//      while (j<array.length){
//        if (array[j] > array[index]){
//          index = j;
//        }
//        j ++;
//      }
//      array[i] = array[index];
//      array[index] = target;
//    }
  }



* 快速排序 简单明了的解释
适用:适用于大量数据,线性结构 短处:数据大量重复时性能不好,不用于单向链式结构。
原理+步骤:
采用分治法,设定low 和 high两个指针,每当一个元素位置定位成功后,递归调用,low,high重新设定,选择排序的加强版,从头和尾部各一个指针进行排序,从头取第一个数据,那么从尾部开始遍历,每次找到对应大小数据就变化遍历位置,直到所有数据排序完成。
1.设定low 和 high两个指针,取头数据,从尾部遍历,即high指针位置
2.如果数据可交换,则将此时指针位置数据设置到另一指针位置。然后指针变换。直到最后位置确定。如:

3.递归,重新设定low和high,并将此过程分为两段,重复1,2,3。直到所有数据完成排序。

  /**
   * 快速排序
   * 双指针,分治法
   * 1.取第一个数 从首尾
   * 2.按取数位置从反向开始遍历
   * 3.将符合的数据填入指针所在位置,变换方向
   * 4.递归直到排序完成
   */
  public void quickSort(int[] array, int begin, int end) {
    if (end - begin <= 0) return;
    int low = begin;
    int high = end;
    boolean orientation = true;
    int target = array[low];
    l1:
    while (low < high) {
      if (orientation) {
        for (int i = high; i > low; i--) {
          if (target >= array[i]) {
            array[low] = array[i];
            low++;
            high = i;
            orientation = !orientation;
            continue l1;
          }
        }

        high = low;
      } else {
        for (int i = low; i <= high; i++) {
          if (target <= array[i]) {
            array[high] = array[i];
            high--;
            low = i;
            orientation = !orientation;
            continue l1;
          }
        }
        low = high;
      }
    }

    //此时low = high
    array[low] = target;
    quickSort(array, begin, low - 1);
    quickSort(array, high + 1, end);

  }

解读代码:
如以上代码所示,设定boolean进行方向处理。完成一个数的定位后,记录这个数的位置,然后递归从此数两端开始重新处理。

* 归并排序(后序排序)
适用:适用数据量大,复用多,链式结构 短处是:空间占用多
原理+步骤:
采用分治法,将若干个元素分为最小单元。从最小单元开始向上层治理。如图:
 
1.创建底层比较方法。
2.创建合并的递归方法。
3.执行递归方法。

 /**
   * 归并排序,分治法
   * left 和 right 都是下标
   */
  public void mergeSort(int[] array, int left, int right) {
    if (right - left <= 0) return;
    int mid = (left + right) / 2;

    //这里找到中点,那么左端是 left - mid,  右端是 mid+1 - right
    mergeSort(array, left, mid);
    mergeSort(array, mid + 1, right);

    //递归到最后的最小单位就是 两个数   此时 left=0,right=1,mid = 1
    merge(array, left, mid + 1, right);
  }

  public void merge(int[] array, int left, int mid, int right) {
    int leftSize = mid - left;
    int rightSize = right - mid + 1;

    int[] leftArray = new int[leftSize];
    int[] rightArray = new int[rightSize];

    for (int i = 0; i < leftSize; i++) {
      leftArray[i] = array[left + i];
    }

    for (int i = 0; i < rightSize; i++) {
      rightArray[i] = array[mid + i];
    }

    int i = 0, j = 0;
    int k = left;
    while (i < leftSize && j < rightSize) {
      if (leftArray[i] < rightArray[j]) {
        array[k] = leftArray[i];
        k++;
        i++;
      } else {
        array[k] = rightArray[j];
        k++;
        j++;
      }
    }


    while (i < leftSize) {
      array[k] = leftArray[i];
      k++;
      i++;
    }

    while (j < rightSize) {
      array[k] = rightArray[j];
      k++;
      j++;
    }
  }

代码解读:
比较的方法的底层元素不只两个。因为从底到顶,最后的元素是 4 - 4,即:

最后是两个有序数组比较。


* 链式基数排序
适用:关键字排序或麻将,扑克等分类排序处理。短处:不适用大数据,链式处理导致内存占用多。
原理+步骤:
排序有点像HashTable,链式结构存储数据然后遍历出来就是排序好的数据,按同类型分,相同类型用链式存储。应用场景:如关键字排序。
例子:链表基数: 1 2 3 4 类,1 中建立链表: a 指向 b ,b 指向 c ,按序形成链表。

麻将的例子:
1.按大小分类,建立链表
2.在1的基础上找出的数组再按类型建立链表
3.此时就是已经有序的数据。


此次代码,我只做了按顺序设置链表,并未做分类。代码步骤如下
1.创建链表数据类
2.按大小进行位置插入
3.从根节点开始遍历到最后,此时的数据就是排序好的


  /**
   * 大多用于分类
   * 如麻将,用到大小和类型
   * 步骤:
   * 1.按大小创建链表
   * 2.在1的基础上,按类型分,创建一次链表
   * <p>
   * 此时数据就是按筒 万  条,三种类型分出,并排序好了
   *
   *
   * 这里多说一点的是:链式基数排序,主要在于先分基数然后按链式结构处理
   * 如:我们排序很多整数数据时,可以按尾数0-9来分类,再按大小分类 或是  按位数来分,按大小再分。这只是一个例子。分类就是基数
   *
   * 上面的麻将的例子就是:类型分创建链表,然后大小再分创建链表。最后取值就是按类型有序的
   *
   *
   * 下面的代码是按大小创建链表的例子。
   *
   * @param array
   * @param start
   * @param end
   */
  public void linkSort(int[] array, int start, int end) {
    int linkSize = end - start;
    for (int i = 0; i < linkSize; i++) {
      insertLink(array[start+i]);
    }

    LinkData linkData = root;
    int i = 0;
    while (linkData!=null){
      array[i] = linkData.data;
      i++;
      linkData=linkData.next;
    }

  }

  LinkData root;


  public void insertLink(int data) {
    LinkData linkData = new LinkData();
    linkData.data = data;
    if (root == null) {
      root = linkData;
      return;
    }

    LinkData lastData = root;
    while (true) {
      if (lastData.data <= data) {
        if (lastData.pre!=null){
          lastData.pre.next = linkData;
        }else {
          root = linkData;
        }
        linkData.pre = lastData.pre;
        linkData.next = lastData;
        lastData.pre = linkData;
        return;
      }


      if (lastData.next == null) {
        lastData.next = linkData;
        linkData.pre = lastData;
        return;
      } else {
        lastData = lastData.next;
      }
    }
  }

  class LinkData {
    LinkData next;
    LinkData pre;
    int data;
  }

* 插入排序
适用:大数据且重复比较多时。 短处:数据大重复少时,排序速度相对插入排序慢。数据小时,速度慢。
原理+步骤:
核心是:多比较少交换,减小资源消耗。
其和选择排序有点相似,但是插入排序是从整个数组前面开始遍历,从后面开始向前对比,如有较大或较小数据,则将对比位置的数据设置到当前位置。最后将最后位置的数据设置为标记数据。
1.从当前位置与前一位对比,符合交换就将前一位数据后移,记录前一位数据交换前的位置
2.重复步骤1,直到数据排列完成。
 

 /**
   * 简单插入排序
   *
   * @param array
   */
  public void insertSort(int[] array) {
    for (int i = 1; i < array.length; i++) {
      int j = i;
      int target = array[j];
      while (j > 0 && array[j - 1] > target) {
        array[j] = array[j - 1];
        j--;
      }
      array[j] = target;
    }
  }

代码解读:
分为外层循环和内存循环。
外层循环用于:加入数据
内存循环用于交换位置,找到符合数据插入的位置。并后移插入位置之后的所有数据



* 希尔排序  (插入排序升级版,且其最后一次执行时必须执行步长为1 的基础插入排序)
适用:使用于大量数据,比插入和堆排序快,但大量数据时比快速排序慢,重复数据多时比快速排序适用。
短处:小数据不适用,大量数据重复少时不如快速排序
原理+步骤:
插入排序的升级版  ,采用步长的策略,设定步长,进行插入排序,但是最后都要走一遍步长为1的基础插入排序。由于之前的步长策略,进一步减小了交换,减少资源消耗。
其步骤和插入一样,不过增加了步长。
 

 /**
   * 1 3
   * 希尔排序
   * 插入排序的增强版,增加步长设置
   * <p>
   * 1.确定循环次数为 步长
   * 2.走简单排序,但是每次查找的数据以步长为单位而不是 1
   * <p>
   * 调用时最后一步必须把步长设置为1
   */
  public void shellSort(int[] array, int stepSize) {
    for (int k = 0; k < stepSize; k++) {
      //这里走简单插入排序
      for (int i = 0; i < array.length; i++) {
        int j = i;
        int target = array[j];

        while (j > stepSize - 1 && array[j - stepSize] < target) {
          array[j] = array[j - stepSize];
          j = j - stepSize;
        }
        array[j] = target;
      }
    }
  }

调用时:最后一步必须步长为 1,执行基础插入排序
 

   int[] array =new int[]{2, 5, 3, 1, 0, 8, 16, 20, 15, 14};

   shellSort(array,4);
   shellSort(array,1);

 

* 堆排序   
适用:超大数据中查找前n个数据时。短处:仅仅适用于数据特别大,且只找寻前n个数据时。其他情况速度慢而且时间长。
原理+步骤:
利用堆这种数据结构进行排序,堆结构类似完全二叉树,满足堆积的性质即其子节点的数据总是小于或大于父节点。堆排序,就是每次建立堆,然后取出根节点。
父节点必须比其子节点大或小,并以此调整堆。


需知:当前节点为k,则父节点为(k-1)/2,左孩子为(2*k)+1,右孩子为(2*k)+2。
1.建立堆排序及调整方法
2.建堆,循环调整。
3.将堆中根节点与最后一个节点交换。然后再重复步骤2,3。最后结果遍历出来的数据就是有序的。

/**
   * 调整堆
   */
  public void maxHeapify(int[] array, int start, int end) {
    int dad = start;//当前开始节点开始调整
    int son = dad * 2 + 1;//左孩子

    while (son <= end) {
      if (son + 1 <= end && array[son + 1] > array[son]) {
        son++;
      }

      if (array[son] > array[dad]) {
        int temp = array[dad];
        array[dad] = array[son];
        array[son] = temp;

        dad = son;//当前开始节点开始调整
        son = dad * 2 + 1;//左孩子
      } else {
        return;
      }
    }
  }

  /**
   * @param array
   * @param len   是排序的起点,是从数组后往前排序,len-1 是数组下标
   */
  public void heapSort(int[] array, int len) {
    //建堆,堆是一个近似完全二叉树的数据结构所以可通过 (k - 1)/ 2 找到父节点
    //len的下标是len-1 ,所以其父节点是(len - 1 - 1)/2 = len/2 -1
    for (int i = len / 2 - 1; i >= 0; i--) {
      maxHeapify(array, i, len - 1);
    }

    //建堆和排序后,将根节点与最后的叶子节点交换
    for (int i = len - 1; i >= 0; i--) {
      int temp = array[0];
      array[0] = array[i];
      array[i] = temp;
      maxHeapify(array, 0, i - 1);
    }
  }

解读代码:

堆排序,就是从传入节点位置开始向其子节点进行调整,如果左孩子和右孩子中的最大值比父节点大,那么就需要调整,交换父节点和其孩子,并判断交换后对孩子的子节点是否有影响,有影响就要继续调整。

 

总结:此文中代码都已经经过测试。八大排序点的原理就写到这了。都是我的个人理解。有不对的地方请指出,谢谢。希望大家能看的明白~

TEST CODE

 public void test() {
    int[] array =new int[]{2, 5, 3, 1, 0, 8, 16, 20, 15, 14};
//    quickSort(array,0,array.length-1);
//    bubbleSort(array);
//    selectSort(array);
//    insertSort(array);
//    mergeSort(array,0,array.length-1);

//    shellSort(array,4);
//    shellSort(array,1);

//    heapSort(array,array.length);
    linkSort(array,0,array.length);
    for (int i :array){
      Log.e("quickSort", "-> "+i );
    }


  }

 

全部代码

import android.util.Log;

/**
 * <p>
 * 八大排序算法
 * <p>
 * 冒泡排序(暴力排序)  适用于小数据,8个以内数据最快
 * 选择排序  适用于小数据,8个以内数据最快。采用遍历数组,找到最小或最大数据的下标,然后交换。
 * 快速排序  采用分治法,设定low 和 high两个指针,每当一个元素位置定位成功后,递归调用,low,high重新设定,选择排序的加强版,从头和尾部各一个指针进行排序,从头取第一个数据,那么从尾部开始遍历,每次找到对应大小数据就变化遍历位置,直到所有数据排序完成
 * 适用于大量数据,线性结构  短处:数据大量重复时性能不好,不用于单向链式结构
 * 归并排序(后序排序) 采用分治法,将若干个元素分为最小单元,适用数据量大,复用多,链式结构  短处是:空间占用多
 * 链式基数排序: 排序有点像HashTable,链式结构存储数据然后遍历出来就是排序好的数据,按同类型分,相同类型用链式存储。应用场景:如关键字排序。
 * ps : 1 2 3 4 类,1 中建立链表: a 指向 b ,b 指向 c ,按序形成链表
 * <p>
 * 插入排序  和选择排序有点相似,但是插入排序是从整个数组后面开始向前对比,如有较大或较小数据,则将对比位置的数据设置到当前位置。最后将最后位置的数据设置为标记数据
 * 多比较少交换,减小资源消耗
 * 希尔排序  插入排序的升级版  ,采用步长的策略,设定步长,进行插入排序,但是最后都要走一遍步长为1的基础插入排序。由于之前的步长策略,进一步减小了交换,减少资源消耗
 * 使用于大量数据,比插入和堆排序快,但大量数据时比快速排序慢,重复数据多时比快速排序适用。
 * <p>
 * 堆排序    利用堆这种数据结构进行排序,堆结构类似完全二叉树,满足堆积的性质即其子节点的数据总是小于或大于父节点。堆排序,就是每次建立堆,然后取出根节点。
 * 应用:大数据查找前n个数据,也就是说仅仅适用于数据特别大,且只找寻前n个数据时。其他情况速度慢而且时间长。
 */

public class SortTest {


  public void test() {
    int[] array =new int[]{2, 5, 3, 1, 0, 8, 16, 20, 15, 14};
//    quickSort(array,0,array.length-1);
//    bubbleSort(array);
//    selectSort(array);
//    insertSort(array);
//    mergeSort(array,0,array.length-1);

//    shellSort(array,4);
//    shellSort(array,1);

//    heapSort(array,array.length);
    linkSort(array,0,array.length);
    for (int i :array){
      Log.e("quickSort", "-> "+i );
    }


  }

  /**
   * 冒泡排序,相邻数据比较,交换
   */
  public void bubbleSort(int[] array) {
    for (int i = 0; i < array.length; i++) {
      boolean flag = true;
      for (int j = 0; j < array.length - 1 - i; j++) {
        if (array[j] < array[j + 1]) {
          int x = array[j];
          array[j] = array[j + 1];
          array[j + 1] = x;

          flag = false;
        }
      }

      if (flag) {
        break;
      }
    }
  }

  /**
   * 选择排序
   */
  public void selectSort(int[] array) {

    int index;
    int target;
    for (int i = 0; i < array.length; i++) {
      index = i;
      for (int j = i + 1; j < array.length; j++) {
        if (array[j] < array[index]) {
          index = j;
        }
      }

      if (index != i) {
        target = array[index];
        array[index] = array[i];
        array[i] = target;
      }
    }

//    int index ;
//    int j;
//
//    int target;
//    for (int i = 0; i < array.length; i++) {
//      target = array[i];
//      index = i;
//      j = i+1;
//      while (j<array.length){
//        if (array[j] > array[index]){
//          index = j;
//        }
//        j ++;
//      }
//      array[i] = array[index];
//      array[index] = target;
//    }
  }

  /**
   * 快速排序
   * 双指针,分治法
   * 1.取第一个数 从首尾
   * 2.按取数位置从反向开始遍历
   * 3.将符合的数据填入指针所在位置,变换方向
   * 4.递归直到排序完成
   */
  public void quickSort(int[] array, int begin, int end) {
    if (end - begin <= 0) return;
    int low = begin;
    int high = end;
    boolean orientation = true;
    int target = array[low];
    l1:
    while (low < high) {
      if (orientation) {
        for (int i = high; i > low; i--) {
          if (target >= array[i]) {
            array[low] = array[i];
            low++;
            high = i;
            orientation = !orientation;
            continue l1;
          }
        }

        high = low;
      } else {
        for (int i = low; i <= high; i++) {
          if (target <= array[i]) {
            array[high] = array[i];
            high--;
            low = i;
            orientation = !orientation;
            continue l1;
          }
        }
        low = high;
      }
    }

    //此时low = high
    array[low] = target;
    quickSort(array, begin, low - 1);
    quickSort(array, high + 1, end);

  }

  /**
   * 简单插入排序
   *
   * @param array
   */
  public void insertSort(int[] array) {
    for (int i = 1; i < array.length; i++) {
      int j = i;
      int target = array[j];
      while (j > 0 && array[j - 1] > target) {
        array[j] = array[j - 1];
        j--;
      }
      array[j] = target;
    }
  }

  /**
   * 1 3
   * 希尔排序
   * 插入排序的增强版,增加步长设置
   * <p>
   * 1.确定循环次数为 步长
   * 2.走简单排序,但是每次查找的数据以步长为单位而不是 1
   * <p>
   * 调用时最后一步必须把步长设置为1
   */
  public void shellSort(int[] array, int stepSize) {
    for (int k = 0; k < stepSize; k++) {
      //这里走简单插入排序
      for (int i = 0; i < array.length; i++) {
        int j = i;
        int target = array[j];

        while (j > stepSize - 1 && array[j - stepSize] < target) {
          array[j] = array[j - stepSize];
          j = j - stepSize;
        }
        array[j] = target;
      }
    }
  }

  /**
   * 归并排序,分治法
   * left 和 right 都是下标
   */
  public void mergeSort(int[] array, int left, int right) {
    if (right - left <= 0) return;
    int mid = (left + right) / 2;

    //这里找到中点,那么左端是 left - mid,  右端是 mid+1 - right
    mergeSort(array, left, mid);
    mergeSort(array, mid + 1, right);

    //递归到最后的最小单位就是 两个数   此时 left=0,right=1,mid = 1
    merge(array, left, mid + 1, right);
  }

  public void merge(int[] array, int left, int mid, int right) {
    int leftSize = mid - left;
    int rightSize = right - mid + 1;

    int[] leftArray = new int[leftSize];
    int[] rightArray = new int[rightSize];

    for (int i = 0; i < leftSize; i++) {
      leftArray[i] = array[left + i];
    }

    for (int i = 0; i < rightSize; i++) {
      rightArray[i] = array[mid + i];
    }

    int i = 0, j = 0;
    int k = left;
    while (i < leftSize && j < rightSize) {
      if (leftArray[i] < rightArray[j]) {
        array[k] = leftArray[i];
        k++;
        i++;
      } else {
        array[k] = rightArray[j];
        k++;
        j++;
      }
    }


    while (i < leftSize) {
      array[k] = leftArray[i];
      k++;
      i++;
    }

    while (j < rightSize) {
      array[k] = rightArray[j];
      k++;
      j++;
    }
  }


  /**
   * 堆排序
   * <p>
   * 1.建堆
   * 2.处理堆
   * 3.拿出根节点,执行2
   */

  /**
   * 调整堆
   */
  public void maxHeapify(int[] array, int start, int end) {
    int dad = start;//当前开始节点开始调整
    int son = dad * 2 + 1;//左孩子

    while (son <= end) {
      if (son + 1 <= end && array[son + 1] > array[son]) {
        son++;
      }

      if (array[son] > array[dad]) {
        int temp = array[dad];
        array[dad] = array[son];
        array[son] = temp;

        dad = son;//当前开始节点开始调整
        son = dad * 2 + 1;//左孩子
      } else {
        return;
      }
    }
  }

  /**
   * @param array
   * @param len   是排序的起点,是从数组后往前排序,len-1 是数组下标
   */
  public void heapSort(int[] array, int len) {
    //建堆,堆是一个近似完全二叉树的数据结构所以可通过 (k - 1)/ 2 找到父节点
    //len的下标是len-1 ,所以其父节点是(len - 1 - 1)/2 = len/2 -1
    for (int i = len / 2 - 1; i >= 0; i--) {
      maxHeapify(array, i, len - 1);
    }

    //建堆和排序后,将根节点与最后的叶子节点交换
    for (int i = len - 1; i >= 0; i--) {
      int temp = array[0];
      array[0] = array[i];
      array[i] = temp;
      maxHeapify(array, 0, i - 1);
    }
  }


  /**
   * 大多用于分类
   * 如麻将,用到大小和类型
   * 步骤:
   * 1.按大小创建链表
   * 2.在1的基础上,按类型分,创建一次链表
   * <p>
   * 此时数据就是按筒 万  条,三种类型分出,并排序好了
   *
   *
   * 这里多说一点的是:链式基数排序,主要在于先分基数然后按链式结构处理
   * 如:我们排序很多整数数据时,可以按尾数0-9来分类,再按大小分类 或是  按位数来分,按大小再分。这只是一个例子。分类就是基数
   *
   * 上面的麻将的例子就是:类型分创建链表,然后大小再分创建链表。最后取值就是按类型有序的
   *
   *
   * 下面的代码是按大小创建链表的例子。
   *
   * @param array
   * @param start
   * @param end
   */
  public void linkSort(int[] array, int start, int end) {
    int linkSize = end - start;
    for (int i = 0; i < linkSize; i++) {
      insertLink(array[start+i]);
    }

    LinkData linkData = root;
    int i = 0;
    while (linkData!=null){
      array[i] = linkData.data;
      i++;
      linkData=linkData.next;
    }

  }

  LinkData root;


  public void insertLink(int data) {
    LinkData linkData = new LinkData();
    linkData.data = data;
    if (root == null) {
      root = linkData;
      return;
    }

    LinkData lastData = root;
    while (true) {
      if (lastData.data <= data) {
        if (lastData.pre!=null){
          lastData.pre.next = linkData;
        }else {
          root = linkData;
        }
        linkData.pre = lastData.pre;
        linkData.next = lastData;
        lastData.pre = linkData;
        return;
      }


      if (lastData.next == null) {
        lastData.next = linkData;
        linkData.pre = lastData;
        return;
      } else {
        lastData = lastData.next;
      }
    }
  }

  class LinkData {
    LinkData next;
    LinkData pre;
    int data;
  }
}

 

链式基数排序麻将的例子代码:

public class ExampleUnitTest {
    @Test
    public void addition_isCorrect() throws Exception {
        LinkedList<Mahjong> list=new LinkedList<Mahjong>();
        list.add(new Mahjong(3,1));
        list.add(new Mahjong(2,3));
        list.add(new Mahjong(3,7));
        list.add(new Mahjong(1,1));
        list.add(new Mahjong(3,8));
        list.add(new Mahjong(2,2));
        list.add(new Mahjong(3,2));
        list.add(new Mahjong(1,3));
        list.add(new Mahjong(3,9));
        System.out.println(list);
        radixSort(list);
        System.out.println(list);
    }
    public static void radixSort(LinkedList<Mahjong> list){
        //先对点数进行分组
        LinkedList[] rankList=new LinkedList[9];
        for (int i = 0; i < rankList.length; i++) {
            rankList[i]=new LinkedList();
        }
        //把数据一个个放到对应的组中
        while(list.size()>0){
            //取一个
            Mahjong m=list.remove();
            //放到组中  下标=点数减1的
            rankList[m.rank-1].add(m);
        }
        //把9组合并在一起
        for (int i = 0; i < rankList.length; i++) {
            list.addAll(rankList[i]);
        }




        //先花色进行分组
        LinkedList[] suitList=new LinkedList[3];
        for (int i = 0; i < suitList.length; i++) {
            suitList[i]=new LinkedList();
        }

        //把数据一个个放到对应的组中
        while(list.size()>0){
            //取一个
            Mahjong m=list.remove();
            //放到组中  下标=点数减1的
            suitList[m.suit-1].add(m);
        }
        //把3个组合到一起
        for (int i = 0; i < suitList.length; i++) {
            list.addAll(suitList[i]);
        }
    }
}



public class Mahjong {
    public int suit;//筒,万,索
    public int rank;//点数 一  二  三

    public Mahjong(int suit, int rank) {
        this.suit = suit;
        this.rank = rank;
    }

    @Override
    public String toString() {
        return "("+this.suit+" "+this.rank+")";
    }
}

//-------------------------------关键LinkList代码--------------------------
public class LinkedList<E> {
    /**
     * 结点
     */
    private static class Node<E> {
        E item;
        Node<E> prev;
        Node<E> next;

        public Node(Node<E> prev, E item, Node<E> next) {
            this.item = item;
            this.prev = prev;
            this.next = next;
        }
    }

    public LinkedList() {

    }

    //头节点
    Node<E> first;
    //尾节点
    Node<E> last;
    //大小
    int size;

    /**
     * 添加数据在最后
     */
    public void add(E e) {
        linkLast(e);
    }

    /**
     * 添加到最后
     * @param e
     */
    private void linkLast(E e) {
        Node<E> newNode = new Node<E>(last, e, null);
        Node<E> l = last;
        last=newNode;

        if(l==null){
            first=newNode;
        }else {
            l.next = newNode;
        }
        size++;
    }
    /**
     * 查找位置
     */
    public E get(int index){
        if(index<0 || index>size){
            return null;
        }
        return node(index).item;
    }
    /**
     * 获取index位置上的节点
     */
    private Node<E> node(int index){

        //如果index在整个链表的前半部分
        if(index<(size>>1)){   //1000 100   10
            Node<E> node=first;
            for (int i = 0; i < index; i++) {
                node=node.next;
            }
            return node;
        }else{
            Node<E> node=last;
            for (int i = size-1; i > index; i--) {
                node=node.prev;
            }
            return node;
        }


    }

    /**
     * 添加数据在index位置
     */
    public void add(int index,E e) {
        if(index<0 || index>size){
            return ;
        }
        if(index==size){
            linkLast(e);
        }else{
            Node<E> target=node(index);//  index=2
            Node<E> pre=target.prev;
            Node<E> newNode=new Node<E>(pre,e,target);

            if(pre==null){
                first=newNode;
                target.prev = newNode;//4
            }else {
                pre.next = newNode;//3
                target.prev = newNode;//4
            }
            size++;
        }

    }

    /**
     * 删除元素
     */
    public void remove(int index){
        Node<E> target=node(index);
        unlinkNode(target);
    }

    private void unlinkNode(Node<E> p) {//index=2
        Node<E> pre=p.prev;
        Node<E> next=p.next;
        if(pre==null){
            first=p.next;
        }else{
            pre.next=p.next;
        }
        if(next==null){
            last=p.prev;
        }else{
            next.prev=p.prev;
        }
        size--;
    }

}

PS:如果觉得有用请点个赞吧~~(≧∇≦)ノ

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值