• 常见排序算法的亲手实现(代码与注释)


      1 package sort;
      2 
      3 import java.util.ArrayList;
      4 import java.util.Random;
      5 
      6 public class Sort
      7 {
      8 
      9     public static Random r = new Random();
     10 
     11     
     12     /**
     13      * 堆排序,建立小顶堆。 0-len是待调整的数组,k指向该次被调整子树的根结点
     14      */
     15 
     16     public static void adjustDown(int arr[], int len, int k)
     17     {
     18         // f = l;
     19         int temp = arr[k];
     20 
     21         for (int i = 2 * k + 1; i <= len; i = 2 * i + 1)
     22         {
     23             // 只有右孩子存在,且右孩子又是小的结点,那么才会改变探索指针i的方向。(i一直指向待调整子树的孩子结点中值较小的结点,为了小顶堆的目标)
     24             if (i < len && arr[i] > arr[i + 1])
     25             {
     26                 i++;
     27             }
     28             if (temp <= arr[i])
     29             {
     30                 break;//要么break出来,要么k继续往下走
     31             }
     32             else
     33             {
     34                 arr[k] = arr[i];
     35                 k = i;// k一直指向,下一轮循环,待调整的子树 的父结点
     36             }
     37         }
     38         arr[k] = temp;// 待调整的k指针没动,直接break出来,没有继续向下调整
     39     }
     40 
     41     // 堆排序,先要建立初始堆(从k到0位置,反复向下调整),然后拿出堆顶(对堆的删除),从根破坏了堆性质,又从根往下调整一次即可。
     42     // 对堆的插入:新结点放在堆的末端,破坏了最下面子树的堆性质,故向上调整到某一次符合堆的性质即可
     43     public static void heapSort(int arr[], int len)
     44     {
     45         // 这个循环建立了初始堆
     46         for (int i = (len - 1) / 2; i >= 0; i--)
     47         {
     48 
     49             adjustDown(arr, len, i);
     50             // Sort.disArr(arr);
     51         }
     52         int temp = 0;
     53         for (int index = len; index >= 0;)
     54         {
     55             temp = arr[0];
     56             arr[0] = arr[index];
     57             arr[index] = temp;
     58             // System.out.println(arr[index] + " ");
     59             // Sort.disArr(arr);
     60             index--;
     61             adjustDown(arr, index, 0);// 固定从整个树的根开始向下调整
     62         }
     63 
     64     }
     65 
     66     // 对小顶堆的插入,插入需要向上调整--AdjustUp
     67     public static void insertHeap(int arr[], int k)
     68     {
     69 
     70         // k为插入结点的位置
     71         int index = k;
     72         int temp = arr[index];// n+1指向新放入的元素
     73         while ((index - 1) / 2 >= 0 && temp < arr[(index - 1) / 2])
     74         {
     75             arr[index] = arr[(index - 1) / 2];// 插入的元素更小,就把父节点值放到子节点中去
     76             index = (index - 1) / 2;// 默认父节点值与temp交换了,一直拿temp去和父辈,父辈的父辈……去比较
     77             if (index == 0)
     78                 break;// 不要在根兜圈圈!减1除2,在0处就不动了
     79         }
     80         arr[index] = temp;
     81     }
     82 
     83     // 利用向上调整,建立初始堆。
     84     // 一边不断插入元素,一边自底(k)向上(0)调整一次。
     85     public static void heapSort(int arr[])
     86     {
     87         // 用直接插入法的思维,一个个点插入堆中,利用向上调整,建立初始堆
     88         for (int i = 0; i <= arr.length - 1; i++)
     89         {
     90             insertHeap(arr, i);
     91         }
     92 
     93         // 还是要用到向下调整,输出序列或进行排序,因为只有堆顶元素具有“最”的特性,输出堆顶元素,从顶破坏了堆的结构,自然需要向下调整。
     94         int temp = 0;
     95         for (int index = arr.length - 1; index >= 0;)
     96         {
     97             temp = arr[0];
     98             arr[0] = arr[index];
     99             arr[index] = temp;
    100             // System.out.println(arr[index] + " ");
    101             // Sort.disArr(arr);
    102             index--;
    103             adjustDown(arr, index, 0);
    104         }
    105     }
    106 
    107     public static void selectSort(int a[])
    108     {
    109         int i = 0, j = 0;
    110         // int restMin = 0;
    111         int index = 0;
    112         int temp = 0;
    113         // 从第0个位置选定元素到第倒数第二个位置,最后只剩一个元素,就不用选定位置了
    114         for (i = 0; i < a.length - 1; i++)
    115         {
    116             // restMin = a[i];//为找到最值做准备;剩下位置中的最小值
    117             index = i;// 必须先初始化为当前位置,因为最值可能就是当前位置的元素嘛
    118             // j指向待比较的元素
    119             for (j = i + 1; j < a.length; j++)
    120             {
    121                 // a[index]值是变化的,用index指向剩下位置中的最小值
    122                 if (a[j] < a[index])
    123                 {
    124                     // restMin = a[j];//restMin保存最小值
    125                     index = j;// 记录最值的位置,同时a[index]自然也记录了最值的大小
    126                 }
    127             }
    128             // swap 交换最小值和当前位置元素的值
    129             if (index != i)
    130             {
    131                 temp = a[i];
    132                 a[i] = a[index];
    133                 a[index] = temp;
    134             }
    135 
    136         }
    137     }
    138 
    139     // 合并段中,把mid位置的放前后和后段,会影响mid取值的计算,以及边界的控制。
    140     public static void merge(int a[], int left, int mid, int right)
    141     {
    142         if (left >= right)
    143             return;
    144 
    145         int index1 = 0;// 游标指向合并中的一段[0 到 mid-left-1],检测指针
    146         int index2 = mid - left;// 游标指向合并中的另一段[mid-left- right - left]
    147         int k = left;// 指向合并后序列的位置,存放指针
    148 
    149         // 在a中取原数据, 在b上合并,再把最终结果保存回原来的数组a;或者copy数据到b,把合并后结果直接覆盖到a上
    150         int b[] = new int[right - left + 1];
    151 
    152         for (int i = 0; i < right - left + 1; i++)
    153         {
    154             b[i] = a[left + i];
    155         }
    156 
    157         while (index1 <= mid - left - 1 && index2 <= right - left)
    158         {
    159             if (b[index1] <= b[index2])
    160             {
    161                 a[k++] = b[index1++];
    162             }
    163             else
    164             {
    165                 a[k++] = b[index2++];
    166             }
    167         }
    168 
    169         while (index1 <= mid - left - 1)
    170         {
    171             a[k++] = b[index1++];// 没有检测完的,复制
    172         }
    173         while (index2 <= right - left)
    174         {
    175             a[k++] = b[index2++];
    176         }
    177     }
    178 
    179     public static void mergeSort(int a[], int left, int right)
    180     {
    181         if (left >= right)
    182             return;
    183         int mid = (left + right) / 2 + 1;
    184         mergeSort(a, left, mid - 1);
    185         mergeSort(a, mid, right);
    186         merge(a, left, mid, right);
    187 
    188     }
    189 
    190     /**
    191      * 
    192      * 交换排序之冒泡排序,结果升序排列
    193      */
    194     public static void bubbleSort(int a[])
    195     {
    196         int i = 0, j = 0, temp = 0;
    197         boolean swaped = false;
    198         // i,控制趟数,n个元素排序,最多进行n-1趟
    199         for (i = 0; i < a.length - 1; i++)
    200         {
    201             swaped = false;
    202             // j指向待排序序列,每一趟将一个待排序列中的最大元素放到该序列的最后。会有j+1,所以注意边界控制
    203             for (j = 0; j < a.length - i - 1; j++)
    204             {
    205                 if (a[j] > a[j + 1])
    206                 {
    207                     temp = a[j];
    208                     a[j] = a[j + 1];
    209                     a[j + 1] = temp;
    210                     swaped = true;
    211                 }
    212             }
    213             if (swaped == false)
    214             {
    215                 return;// 本趟无逆序,停止处理
    216             }
    217         }
    218     }
    219 
    220     /**
    221      * 交换排序之快速排序
    222      */
    223 
    224 
    225     public static int partition(int a[], int left, int right)
    226     {
    227         // 基准元素的选择对于快速排序性能影响较大;index
    228         int index = left + r.nextInt(right - left + 1);// 随机选基准元素,把它放到a[left]哨兵位置,然后从right开始扫描,才是正确的
    229         
    230 
    231         int value = a[index];// 用value保存了当前选取的枢轴元素,就可腾空一个位置
    232 
    233         // 一定把枢轴元素交换至最左边(放到最左就从right开始检测,最右就应该从left开始检测),使得腾空的位置从最边上向枢轴的真正位置逼近!而不是一开始就从枢轴元素的起始位置开始移动
    234 
    235         int temp = a[left];
    236         a[left] = a[index];
    237         a[index] = temp;
    238 
    239         while (left < right)
    240         {
    241             // 比较中带等号,针对重复元素如:4,3,4,检测指针才会移动,不然就死循环了
    242 
    243             // 先让右侧开始检测,对于4,9;选了9当value,直接开始right--就不对
    244             while (left < right && a[right] >= value)
    245             {
    246                 right--;
    247             }
    248             a[left] = a[right];
    249             
    250             while (left < right && a[left] <= value)
    251             {
    252                 left++;
    253             }
    254             a[right] = a[left];
    255             
    256         }
    257         // 必然left==right了
    258         a[left] = value;
    259         return left;
    260     }
    261 
    262     public static void quikSort(int a[], int left, int right)
    263     {
    264         if (left >= right)
    265             return;
    266         int p = partition(a, left, right);
    267         quikSort(a, left, p - 1);
    268         quikSort(a, p + 1, right);
    269     }
    270 
    271     /**
    272      * 直接插入排序,结果为升序
    273      * 
    274      * @param a
    275      */
    276     
    277 //两个指针,一个指向待插入元素,一个指向已经排好序的序列
    278     public static void insertSort(int a[], int left, int right)
    279     {
    280         int i = 0, j = 0, temp = 0;
    281         // i 指向待排序的元素。实际应用时:就是传入参数left = 0,right = a.lenght-1;
    282         for (i = left + 1; i <= right; i++)
    283         {
    284             // 如果带排序元素需要往前插入,就不断后移动元素;如果不需要,就什么不做,直接考察下一个元素
    285             if (a[i] < a[i - 1])
    286             {
    287                 temp = a[i];// temp保存了待插入的元素
    288                 j = i - 1;// j指向了i之前已经有序的段
    289                 do
    290                 {
    291                     a[j + 1] = a[j];
    292                     j--;
    293 
    294                 } while (j >= left && temp < a[j]);
    295                 a[j + 1] = temp;// 插入temp
    296             }
    297         }
    298     }
    299 
    300     public static void binaryInsertSort(int arr[],int left,int right)
    301     {
    302         int i=0,j=0,temp=0,high = 0,low=0,middle=0;
    303         for(i=left+1;i<=right;i++)
    304         {
    305             temp = arr[i];
    306             low = left;
    307             high = i-1;
    308             while(low<=high)
    309             {
    310                 middle = (low+high)/2;
    311                 if(temp < arr[middle])
    312                 {
    313                     high = middle - 1;
    314                 }
    315                 else
    316                 {
    317                     low = middle + 1;
    318                 }
    319             }
    320             for(j=i-1;j>=low;j--)
    321             {
    322                 arr[j+1] = arr[j];
    323             }
    324             arr[low] = temp;
    325         }
    326     }
    327     
    328     public static void main(String []args)
    329         {
    330 
    331         }
    332 }
    333         
  • 相关阅读:
    B树与B+详解
    SQLite占用资源少原因
    iOS SQLite详解
    YTKNetwork网络封装
    YTKNetwork源码详解
    AFNetworking封装-项目使用
    iOS网络请求-AFNetworking源码解析
    PHP 不使用第三个变量实现交换两个变量的值
    PHP public private protected 三种修饰符的区别
    PHP 汉字转拼音
  • 原文地址:https://www.cnblogs.com/yongwangzhiqian/p/3978088.html
Copyright © 2020-2023  润新知