排序算法的实例

写了一下排序算法的一些实例,Java语言写的,从网上也是各种找,各种测试,整理了一下,方便学习极客时间专栏-数据结构与算法:作者是王争。

  1     //二路归并排序中计算排序次数
  2     public static int number = 0;
  3
  4     /**
  5      * 冒泡排序的算法  关键是先排列出最大的数 依次从大到小进行排序
  6      *
  7      * 算法描述:
  8      * 1.比较相邻的元素,如果第一个比第二个大,就交换它们两个
  9      * 2.对每一个相邻的元素做同样的工作,从开始的第一队,到结束的最后一对,这样在最后的元素应该是最大的数
 10      * 3.针对所有的元素重复以上步骤,除了最后一个
 11      * 4.重复步骤1~3,知道排序完成
 12      *
 13      * @param arr 需要排序的数组元素,这里只针对整数,当然其他的也可以
 14      * @return
 15      */
 16     public int[] bubbleSort(int[] arr){
 17
 18         int len = arr.length;
 19
 20         for(int i=0; i<len-1; i++){
 21             //其实 len-1-i 说明的是第二个循环每次不用全部循环  只需要循环还没有排列出顺序的数
 22             for(int j=0; j<len-1-i; j++){
 23                 //相邻两元素 两两对比
 24                 if(arr[j] > arr[j+1]){
 25                     //元素交换 把大数放在后面
 26                     int temp = arr[j+1];
 27                     arr[j+1] = arr[j];
 28                     arr[j] = temp;
 29                 }
 30             }
 31         }
 32         return arr;
 33     }
 34
 35     /**
 36      * 选择排序算法  是一种简单直观的算法,在未排序的序列中找到最小(大)数,存放在数列起始的位置,
 37      *          然后在从剩余的数列中寻找最小(大),放在已排序数列的末尾
 38      *
 39      * 算法描述:
 40      * 1.初始状态:无序区为R[1..n],有序区为空
 41      * 2.第i(i=1,2,3,..,n)趟排序开始时,当前有序区和无序区分别为R[1..i-1]、R[i..n],该趟排序从当前无序区中选出关键字最小的记录
 42      * R[k],将他和无序区的最后一个R交换,使R[1..i]和R[i+1..n-1]分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区
 43      * 3.n-1趟结束,数据有序化了
 44      *
 45      * @param arr 待排序的整数数组
 46      * @return 排序完成
 47      */
 48     public int[] selectionSort(int[] arr){
 49
 50         int len = arr.length;
 51         int minIndex;
 52         int temp;
 53
 54         // arr len=10 最后一个下标即是9
 55         for(int i=0; i<len-1; i++){
 56             minIndex = i;
 57             //j<len 这个不会出现数组越界的问题的因为没有用到 arr[j+1]
 58             for(int j=i+1; j<len; j++){
 59                 //寻找为排序的数列中最小的数
 60                 if(arr[j] < arr[minIndex]){
 61                     //将最小的数的索引保存
 62                     minIndex = j;
 63                 }
 64             }
 65             //将两个数交换位置,之后继续排序,直到排序完成
 66             temp = arr[i];
 67             arr[i] = arr[minIndex];
 68             arr[minIndex] = temp;
 69         }
 70         return arr;
 71     }
 72
 73     /**
 74      * 插入排序算法  通过构建有序数列,对于未排序数据,在已排序的序列中从后向前扫描,找到相应的位置并插入
 75      *
 76      * 算法描述:
 77      * 1.从第一个元素开始,该元素可以被认为已经被排序
 78      * 2.取出下一个元素,在已经排序的序列中从后向前扫描
 79      * 3.如果该元素(已排序)大于新元素,将该元素移到下一位置
 80      * 4.重复步骤三,直到找到已排序的元素小于或者等于新元素的位置
 81      * 5.将新元素插入到该位置后
 82      * 6.重复步骤2~5
 83      *
 84      * 问题:
 85      * 这段排序的程序有点难以理解!!!大概是明白了
 86      *
 87      * @param arr 待排序的整数数组
 88      * @return 排序完成
 89      */
 90     public int[] insertionSort(int[] arr){
 91
 92         int len = arr.length;
 93         int preIndex;
 94         int current;
 95
 96         for(int i=1; i<len; i++){
 97             preIndex = i-1;
 98             current = arr[i];
 99
100             //对于preIndex-- 当前的数和已排序数列的数逐次比较大小,在有序数列中找到preIndex下标的数(下标为preIndex的数小于当前数)
101             while(preIndex >= 0 && arr[preIndex] > current){
102                 arr[preIndex+1] = arr[preIndex];
103                 preIndex--;
104             }
105             //结束while循环则表示当前数 大于或者等于有序数列中下标为preIndex的一个数,则把当前数 放在这个数的后面
106             arr[preIndex+1] = current;
107         }
108         return arr;
109     }
110
111     /**
112      * 希尔排序  1959年,shell发明,第一个突破O(n*n)的排序算法,是简单插入排序的改进版,它会优先比较较远的元素,又叫缩小增量排序
113      *
114      * 算法描述:(先将整个待排序的记录序列分割成若干个子序列分别进行直接插入排序)
115      * 1.选择一个增量序列t1,t2,...,tk 其中ti>tj,tk=1;
116      * 2.按增量序列个数k,对序列进行K趟排序
117      * 3.每趟序列,根据对应的增量ti,将待排序列分割成若干长度为m的子序列,分别对子表进行直接插入排序,
118      *        仅增量因子为1时,整个序列最为一个表来处理,表长度即为整个序列的长度
119      *
120      * 问题:这个有点难以理解,关键是间隔序列的设定,还有就是时间空间复杂度为啥小于O(n*n)
121      *
122      * @param arr 待排序的整数数组
123      * @return 排序完成
124      */
125     public int[] shellSort(int[] arr){
126
127 //        long startTime=System.currentTimeMillis();   //获取开始时间
128 //        System.out.println("程序运行开始时间: "+startTime);
129
130         int len = arr.length;
131         int gap = 1;
132         int temp;
133         int j;
134
135         //动态定义间隔序列
136         while(gap < len/3){
137             gap = gap * 3 + 1;
138         }
139
140         for(; gap>0; gap=(int) Math.floor(gap/3)){
141             for(int i=gap; i<len; i++){
142                 temp = arr[i];
143                 for(j=i-gap; j>0 && arr[j]>temp; j-=gap){
144                     arr[j+gap] = arr[j];
145                 }
146                 arr[j+gap] = temp;
147             }
148         }
149         return arr;
150     }
151
152     /**
153      * 二路归并排序的算法  归并排序是建立在归并操作上的一种排序算法   先使子序列有序,再使子序列段间有序
154      *
155      * 算法描述:
156      * 1.将长度为n的序列分成长度为2/n的两个子序列
157      * 2.对这两个子序列分别进行归并排序
158      * 3.将排序好的子序列合并成一个最终的合并序列
159      *
160      * 问题:
161      * 这个归并排序算法 对于奇数个数的数组 好像还是有点问题
162      *
163      * @param arr 待排序的数组序列
164      * @return 排序完成
165      */
166     public void mergeSort(int[] arr){
167
168         System.out.println("开始排序~~~");
169         int len = arr.length - 1;
170         sort(arr, 0 , len-1);
171     }
172
173     private void sort(int[] arr, int left, int right){
174
175         if(left >= right){
176             return;
177         }
178
179         int mid = (left + right)/2;
180         System.out.println("middle的数是:>>>>>>>>>>>>"+mid);
181         //二路归并排序有两个sort 多路归并排序写多个sort就可以了
182         sort(arr, left, mid);
183         sort(arr, mid+1, right);
184         merge(arr, left, mid, right);
185
186     }
187
188     private void merge(int[] arr, int left, int mid, int right){
189
190         int[] tmp = new int[arr.length];
191         int r1 = mid + 1;
192         int tIndex = left;
193         int cIndex = left;
194
195         //逐个合并
196         while(left <= mid && r1 <= right){
197             if(arr[left] < arr[r1]){
198                 tmp[tIndex++] = arr[left++];
199             }else{
200                 tmp[tIndex++] = arr[r1++];
201             }
202         }
203
204         //将左边剩余 的合并
205         while(left <= mid){
206             tmp[tIndex++] = arr[left++];
207         }
208
209         //将右边剩余的合并
210         while(r1 <= right){
211             tmp[tIndex++] = arr[r1++];
212         }
213
214         System.out.println("第"+(++number)+"趟排序:\t");
215         //从临时数组拷贝到原数组
216         while(cIndex <= right){
217             arr[cIndex] = tmp[cIndex];
218             System.out.print(arr[cIndex]+"\t");
219             cIndex++;
220         }
221         System.out.println();
222     }
223
224     /**
225      * 快速排序算法:通过一趟排序将待排记录分隔成独立的两部分,其中一部分的关键字均比另一部分的关键字小,
226      *             则可分别对这两部分记录继续排序,从而使整个序列有序
227      *
228      * 算法描述:快速排序算法采用分治法 把一个串分成两个子串
229      * 1.从数列中挑出一个元素,成为“基准”(pivot)
230      * 2.重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)
231      *   在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作
232      * 3.递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序
233      *
234      * @param arr 待排序的数组序列
235      * @return 排序完成
236      */
237     public int[] quickSort(int[] arr, int left, int right){
238
239         int partitionIndex;
240
241         if (left < right) {
242             partitionIndex = partition(arr, left, right);
243             quickSort(arr, left, partitionIndex-1);
244             quickSort(arr, partitionIndex+1, right);
245         }
246         return arr;
247     }
248
249     //快速排序的分区操作
250     private int partition(int[] arr, int left, int right) {
251         //分区操作   设定基准值(pivot)
252         int pivot = left;
253         int index = pivot + 1;
254         for (int i = index; i <= right; i++) {
255             if (arr[i] < arr[pivot]) {
256                 int temp = arr[i];
257                 arr[i] = arr[index];
258                 arr[index] = temp;
259                 index++;
260             }
261         }
262         int temp = arr[pivot];
263         arr[pivot] = arr[index-1];
264         arr[index-1] = temp;
265         return index-1;
266     }
267
268     /**
269      * 计数排序算法
270      * 计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。
271      * 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。
272      *
273      * 算法描述:
274      * 1.找出待排序的最大和最小的数
275      * 2.统计数组中的每个值为i的元素出现的次数,存入数组c的第i项
276      * 3.对所有的计数累加(从C的第一个元素开始,每一项和前一项相加)
277      * 4.反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将c(i)减1
278      *
279      * @param arr 待排序的数组
280      * @return
281      */
282     public int[] countingSort(int[] arr){
283
284         int cnum =0;
285         for(int i = 0 ; i<arr.length;i++){
286             if(cnum < arr[i]) {
287                 cnum = arr[i];
288             }
289         }
290         int[] c = new int[cnum+1];
291         int[] b = new int[arr.length];
292
293         for(int i =0; i<c.length; i++){
294             c[i]=0;
295         }
296
297         for(int i = 0;i<arr.length;i++) {
298             c[arr[i]]+=1;
299         }
300
301         for(int i =1;i<c.length;i++) {
302             c[i]+=c[i-1];
303         }
304
305         for(int i = arr.length-1;i>=0;i--){
306             b[c[arr[i]]-1]=arr[i];
307             c[arr[i]]-=1;
308         }
309         return b;
310     }
311
312     /**
313      *
314      * @param arr 待排序的数组
315      * @param maxDigit
316      * @return
317      */
318     public int[] radixSort(int[] A){
319         int length = A.length;
320
321         // 定义每一轮的除数,1,10,100...
322         int divisor = 1;
323
324         // 定义了10个桶,以防每一位都一样全部放入一个桶中
325         int[][] bucket = new int[10][length];
326
327         // 统计每个桶中实际存放的元素个数
328         int[] count = new int[10];
329
330         // 获取元素中对应位上的数字,即装入那个桶
331         int digit;
332
333         // 经过4次装通操作,排序完成
334         for (int i = 1; i <= 3; i++) {
335             // 计算入桶
336             for (int temp : A) {
337                 digit = (temp / divisor) % 10;
338                 bucket[digit][count[digit]++] = temp;
339             }
340             // 被排序数组的下标
341             int k = 0;
342             // 从0到9号桶按照顺序取出
343             for (int b = 0; b < 10; b++) {
344                 // 如果这个桶中没有元素放入,那么跳过
345                 if (count[b] == 0)
346                     continue;
347                 for (int w = 0; w < count[b]; w++) {
348                     A[k++] = bucket[b][w];
349                 }
350                 // 桶中的元素已经全部取出,计数器归零
351                 count[b] = 0;
352             }
353             divisor *= 10;
354         }
355         return A;
356     }

注释:写到最后越来越难理解,后面的几个算法,基本上都是拷贝的,但是大体的思路是可以理解的,对于时间、空间复杂度分析,还是比较混乱,但是基本上头脑中有了程序优化的一个概念,最重要的一点是二路归并算法的存在一些问题,对于数组的个数为奇数的,总有最后一个数,不参与排序,等跟着专栏学习,看看能不能解决吧,网上的好多方案都不合适。。。(对于堆排序算法和桶排序算法,没有写)

参考的博客有许多,把主要的贴出来吧,望作者见谅

https://www.cnblogs.com/onepixel/articles/7674659.html

这个作者写的有动图的讲解,很形象!
https://www.cnblogs.com/shudonghe/p/3302888.html
https://www.cnblogs.com/haozhengfei/p/29ba40edbf659f2dbc6b429c2818c594.html

下面是测试代码,转载注明出处,谢谢!!!

//测试代码贴出来吧
public static void main(String[] args) {
        Sort sort = new Sort();
        int[] arr = {3,38,5,15,36,26,30,50,29,59,43,62,18};

        //sort.bubbleSort(arr);
        //sort.selectionSort(arr);
        //sort.insertionSort(arr);
        //sort.shellSort(arr);
        //sort.mergeSort(arr);
        //sort.quickSort(arr, 0, arr.length-1);
        //int[] arr1 = sort.countingSort(arr);

        sort.radixSort(arr);

        for(int i=0; i < arr.length; i++){
            System.out.println("第"+(i+1)+"个数是>>>>>>>>>>"+arr[i]);
        }
    }

原文地址:https://www.cnblogs.com/ssh-html/p/9761074.html

时间: 2024-12-19 18:42:33

排序算法的实例的相关文章

GDI+学习笔记(九)带插件的排序算法演示器(MFC中的GDI+实例)

带插件的排序算法演示器 本节将通过一个实例来说明GDI+在MFC中的应用.这个算法演示器其实是本人算法系列的一个开端,由于csdn没有树状的目录结构,咱也只好使用链表了不是?好了,废话不多说,开始今天的文章. (一)功能说明 我们初步制定功能如下: (1). 能够通过柱状图,自动展示排序算法的交换比较过程 (2). 能够使用插件的形式进行开发.即,当新完成一个算法后,只需要完成一个插件文件(我们这里使用动态库dll),由主程序加载插件,即可进行执行,而不再需要重新编译主程序. (3). 保证主程

PHP四大基本排序算法实例

PHP四大基本排序算法包括:冒泡排序法,快速排序法,选择排序法,插入排序法. 1. 冒泡排序 思路分析:在要排序的一组数中,对当前还未排好的序列,从前往后对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒.即,每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换. 代码实现: $arr=array(1,43,54,62,21,66,32,78,36,76,39); function bubbleSort($arr) { $len=count($arr); //该层循环控

算法(第4版)-2.1 初级排序算法

2.1.1 游戏规则 1. 排序成本模型:在研究排序算法时,我们需要计算比较和交换的数量.对于不交换元素的算法,我们会计算访问数组的次数. 2. · 原地排序算法:除了函数调用所需的栈和固定数目的实例变量之外无需额外内存的原地排序算法: · 其他排序算法:需要额外内存空间来储存另一份数组副本. 2.2.2 选择排序 public class Selection { public static void sort(Comparable[] a) { // 将a[]按升序排列 int N = a.l

DotNet常用排序算法总结

数据结构和算法对一个程序来说是至关重要的,现在介绍一下几种算法,在项目中较为常用的算法有:冒泡排序,简单选择排序,直接插入排序,希尔排序,堆排序,归并排序,快速排序等7中算法. 现在介绍选择排序算法,希尔排序算法,快速排序算法. (1).选择排序算法:通过n-i次关键字间的比较,从n-i+1个记录中选择出关键字最小的记录,并和第i(1大于等于i小于等于n)个记录交换. (2).希尔排序:先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组.所有距离为d1的倍数的记录放在同一个组中.先在各

各种排序算法的分析及java实现

各种排序算法的分析及java实现 排序一直以来都是让我很头疼的事,以前上<数据结构>打酱油去了,整个学期下来才勉强能写出个冒泡排序.由于下半年要准备工作了,也知道排序算法的重要性(据说是面试必问的知识点),所以又花了点时间重新研究了一下. 排序大的分类可以分为两种:内排序和外排序.在排序过程中,全部记录存放在内存,则称为内排序,如果排序过程中需要使用外存,则称为外排序.下面讲的排序都是属于内排序. 内排序有可以分为以下几类: (1).插入排序:直接插入排序.二分法插入排序.希尔排序. (2).

八大排序算法

转载:http://blog.csdn.net/hguisu/article/details/7776068 目录(?)[+] 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 我们这里说说八大排序就是内部排序. 当n较大,则应采用时间复杂度为O(nlog2n)的排序方法:快速排序.堆排序或归并排序序. 快速排序:是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速

数据结构杂谈(一)浅谈基本排序算法

0.基本概念 记录:待排序的项目 关键词:决定排序结果 稳定性:相同关键词的记录保持原来的相对次序 1.1插入排序(Insertion Sort) 算法思想 一种简单直观的排序算法,工作原理是通过构建有序序列:对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入. 算法描述 具体算法描述如下: 从第一个元素开始,该元素可以认为已经被排序 取出下一个元素,在已经排序的元素序列中从后向前扫描 如果该元素(已排序)大于新元素,将该元素移到下一位置 重复步骤3,直到找到已排序的元素小于或者等于

排序算法——归并排序

归并排序是分治法的典型举例. 分治法的思想是,将原有问题分解为几个规模较小但类似于原问题的子问题,递归的求解这些子问题,然后再合并这些子问题的解来建立原问题的解. 分治模式在每层递归时都有三个步骤: 分解原问题为若干子问题,这些子问题是原问题的规模较小的实例. 解决这些子问题,递归地求解各子问题.然而,若子问题的规模足够小,则直接求解. 合并这些子问题的解成原问题的解. 归并排序算法完全遵循分治模式.直观上其操作如下: 分解:分解待排序的n个元素的序列成各具n/2个元素的两个子序列. 解决:使用

[转载]图解程序员必须掌握的Java常用8大排序算法

这篇文章主要介绍了Java如何实现八个常用的排序算法:插入排序.冒泡排序.选择排序.希尔排序 .快速排序.归并排序.堆排序和LST基数排序,分享给大家一起学习. 分类1)插入排序(直接插入排序.希尔排序)2)交换排序(冒泡排序.快速排序)3)选择排序(直接选择排序.堆排序)4)归并排序5)分配排序(基数排序) 所需辅助空间最多:归并排序所需辅助空间最少:堆排序平均速度最快:快速排序 不稳定:快速排序,希尔排序,堆排序. 先来看看8种排序之间的关系: 1.直接插入排序 (1)基本思想:在要排序的一