排序专题(六) / 不稳定的内部排序 / 递归 | 非递归的快速排序

  • 时间复杂度:O(nlogn)

  • 无论是递归的还是非递归的快速排序,其关键都是partition方法,每一次partition后,都会找到原序列的pivot(枢轴)索引,且位于pivot索引上的元素一定处于整个最终有序序列它应该位于的正确位置上,显然partition后找到的pivot索引会将原序列不断分裂成两个子序列。如此:所有元素都会找到自己最终应该处于的正确位置,这样整个序列便会有序。

  • 算法导论版快速排序实现思想
    • 每次partition尝试找到每个子序列第一个元素的最终正确位置,且将该元素交换到该位置,并且该最终位置(pivot索引)会将该序列分裂成两个子序列(上面已经说过了哈),如此不断进行,直至序列有序
    • 具体来说:设置最初ultimateIndex=子序列leftIndex,遍历除leftIndex外的子序列,每当找到一个比leftIndex大的元素ultimateIndex加1,如此便可以得到ultimateIndex的值,交换leftIndex元素到ultimateIndex处。在各子序列上不断运行该方法,便可以使整个序列有序。
    •     /*
           *  How to record where the pivot value is?
           *  
           *  Can you give another solution?
           */
          private static int partition(int[] array, int leftIndex, int rightIndex) {
              int ultimateIndex = leftIndex;
              for (int i = leftIndex + 1; i <= rightIndex; i ++) {
                  if (array[i] < array[leftIndex]) {
                      ultimateIndex ++;
                      if (ultimateIndex != i) {
                          swap(array, ultimateIndex, i);
                      }
                  }
              }
              
              if (ultimateIndex != leftIndex) {
                  swap(array, leftIndex, ultimateIndex);
              }
              
              return ultimateIndex;
          }
    •     public static void quickSort(int[] array, int leftIndex, int rightIndex) {
              if (rightIndex > leftIndex) {
                  int pivotIndex = partition(array, leftIndex, array.length - 1);
                  quickSort(array, leftIndex, pivotIndex - 1);
                  quickSort(array, pivotIndex + 1, rightIndex);
              }
          }
  • 严蔚敏版快速排序实现思想
    • partition方法要实现的目的和上面算法导论版的是一样的
    • 具体来说:为每个子序列设置leftIndex和rightIndex,leftIndex从左到右遍历数组,rightIndex从右到左遍历数组,遍历规则如下:
      • 若leftIndex和rightIndex不相遇则就按下规则不断交替移动leftIndex和rightIdnex
      • 必须先从rightIndex指针开始移动,否则需要另设置变量处理一些问题,稍加动手便可以明白这个问题
      • 当rightIndex向左移动的过程中若找到一个小于所给子序列第一个元素的元素,交换此时leftIndex和rightIndex所代表的元素,停止移动rightIndex,开始移动leftIndex;否则一直移动rightIndex
      • 当leftIndex向右移动的过程中若找到一个大于所给子序列第一个元素的元素,交换此时leftIndex和rightIndex所代表的元素,停止移动leftIndex,开始移动rightIndex;否则一直移动leftIndex
      • 如此,直至rightIndex和leftIndex相遇
      • 当rightIndex和leftIndex相遇时,其值就是pivot索引,且子序列的第一个元素应经被交换到该位置上了
    •     private static int partitionYAN(int[] array, int leftIndex, int rightIndex) {
              int i = leftIndex;
              for (int j = rightIndex; i != j;) {
                  while (j > i) {
                      if (array[j] < array[i]) {
                          swap(array, j, i);
                          i ++;
                          break;
                      } else {
                          j --;
                      }
                  }
                  while (i < j) {
                      if (array[i] > array[j]) {
                          swap(array, i, j);
                          j --;
                          break;
                      } else {
                          i ++;
                      }
                  }
              }
              return i;
          }
    •     public static void quickSortYAN(int[] array, int leftIndex, int rightIndex) {
              if (rightIndex > leftIndex) {
                  int pivotIndex = partitionYAN(array, leftIndex, array.length - 1);
                  quickSortYAN(array, leftIndex, pivotIndex - 1);
                  quickSortYAN(array, pivotIndex + 1, rightIndex);
              }
          }

  • 非递归实现的话,有思路就很简单:每次partition后将生成子序列的起始索引和结束索引成对存储进一个栈,只要栈不空,每次弹出一对索引,在其代表的序列上执行快速排序就OK了。
    • public class QuickSort {
          
          public static void quickSort(int[] array) {
              if (array.length <= 1) {
                  return;
              } else {
                  
                  Stack<Integer> indexStack = new Stack<Integer>();
                  indexStack.push(0);
                  indexStack.push(array.length - 1);
                  
                  while (!indexStack.isEmpty()) {
                      
                      int toIndex = indexStack.pop();
                      int fromIndex = indexStack.pop();
                      
                      int ultimateIndex = fromIndex;
                      for (int i = fromIndex + 1; i <= toIndex; i ++) {
                          if (array[i] < array[fromIndex]) {
                              ultimateIndex ++;
                              if (ultimateIndex != i) {
                                  swap(array, ultimateIndex, i);
                              }
                          }
                      }
                      if (ultimateIndex != fromIndex) {
                          swap(array, ultimateIndex, fromIndex);
                      }
                      
                      if (ultimateIndex - 1 > fromIndex) {
                          indexStack.push(fromIndex);
                          indexStack.push(ultimateIndex - 1);
                      }
                      if (ultimateIndex + 1 < toIndex) {
                          indexStack.push(ultimateIndex + 1);
                          indexStack.push(toIndex);
                      }
                  }
              }
          }
          
          public static void quickSortYAN(int[] array) {
              if (array.length <= 1) {
                  return;
              } else {
                  Stack<Integer> indexStack = new Stack<Integer>();
                  indexStack.push(0);
                  indexStack.push(array.length - 1);
                  
                  while (!indexStack.isEmpty()) {
                      
                      int toIndex = indexStack.pop();
                      int fromIndex = indexStack.pop();
                      
                      int i = fromIndex;
                      for (int j = toIndex; i != j;) {
                          while (j > i) {
                              if (array[j] < array[i]) {
                                  swap(array, j, i);
                                  i ++;
                                  break;
                              } else {
                                  j --;
                              }
                          }
                          while (i < j) {
                              if (array[i] > array[j]) {
                                  swap(array, i, j);
                                  j --;
                                  break;
                              } else {
                                  i ++;
                              }
                          }
                      }
                      
                      if (i - 1 > fromIndex) {
                          indexStack.push(fromIndex);
                          indexStack.push(i - 1);
                      }
                      if (i + 1 < toIndex) {
                          indexStack.push(i + 1);
                          indexStack.push(toIndex);
                      }
                  }
              }
          }
          
          private static void swap(int[] array, int index1, int index2) {
              array[index1] ^= array[index2];
              array[index2] ^= array[index1];
              array[index1] ^= array[index2];
          }
      
      }

  • PS:
    • Code还是去年工作半年闲暇时码的,目的是为了弥补自己本科期间没有动手写这些基础code的缺憾
    • 总是工作时抽闲写一点,注释较少,望君手下留情
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值