简单排序的Java实现与效率分析
来源:互联网 发布:淘宝客活动报名技巧 编辑:程序博客网 时间:2024/06/04 20:06
简单排序应该是编程中最基本的,本次分析的简单排序包括冒泡排序、选择排序、插入排序。
冒泡排序是最简单的排序方法,基本上每个程序员都能不假思索,信手拈来。其算法简单,基本逻辑如下:
1.取数组第一个数为基数,并将数组最后一个数标记为标志数。
2.比较基数右边的数,如果基数大于此数,那么就交换两个数,否则不处理。
3.令基数右边的数为新基数,重复2-3步,直到新基数为标志数为止(此数需执行2-3过程)。
4.取数组第一个数为基数,,将原标志数左边的数标记为新标志数,重复2-4步,直到新标志数为第一个数为止(此数不执行2-4过程)。
其代码如下:
选择排序是冒泡排序的优化,虽然比较次数上没有改变,但在交换次数上大大减少。其逻辑如下:
1.在数组取第一个数为基数,令标识位等于基数的下标。
2.依次比较基数右边的数,如果此数小于标识位所指向的数,则令标识位等于此数的下标,直到数组最后一个为止(此数也要比较)。
3.交换基数与标志位所指向的数。
4.取基数右边的数为新基数,令标志数等于新基数的下标,重复2-4过程,直到数组倒数第二个数(此数要比较)。
其代码如下:
插入排序可以说是三者中最好的算法,尤其是在数据局部有序的情况下,其算法逻辑如下:
1.在数组中取第二个数为基数,令缓冲数等于基数值。
2.依次比较基数左边的数,若此数大于基数,则将此数右移(令此数右边的数等于此数。)直到有数小于基数为值(此数不要移动)。
3.令数组最后右移的数等于缓冲数。
4.取数组第三个数为新基数,令缓冲数等于基数值,重复2-4过程,直到最后一个数(此数需执行243过程)。
其代码如下:
从上面看,好像插入排序的算法并不比冒泡和选择简单。但是请注意,如果数组局部有序(那怕只有两个数是有序的),情况就大大不同。例如数组{2,3,4,5,6,1,0},数组中2,3,4,5,6属于局部有序。插入排序时,基数为2,3,4,5,6时,都不用处理,当基数为1时,方法只需要移动6次,基数为0时,移动7次。选择排序需要交换7次,冒泡排序需要交换21次,而一次交换至少需要移动2次。
通过比较我们可以看出,大数据下冒泡排序效率最低,选择排序虽然移动次数最少,但是比较次数高,而插入排序是三者中综合效率最好的。
参考《Java数据结构和算法》一书,冒泡排序交换和比较操作次数为 N*(N-1)/2,是与N2成正比(记作O(N2));选择排序交换虽然为O(N),但是比较时间与冒泡排序相同,还是O(N2);插入排序比较时间为 N*(N-1)/4。而移到次数与插入次数大致相同,两者近似O(N2),但是如果数据局部有有序,While循环基本为假,则算法所需的时间就能蜕变成O(N)。
简单排序一般适用于小数据量,大数据量排序还得高级排序(如快速排序等)。如果大家想深入研究可以参考《Java数据结构和算法》一书。
首先我们准备一个要排序的数组,当然还有一些方法,基本如下:
- private int[] sortInts;//排序数组
- // 初始化sortInts
- public SimpleSorts(int[] sortInts) {
- this.sortInts = sortInts;
- }
- // getter
- public int[] getSortInts() {
- return sortInts;
- }
- // setter
- public void setSortInts(int[] sortInts) {
- this.sortInts = sortInts;
- }
- // 显示数组
- public void display() {
- System.out.println("数组:" + Arrays.toString(sortInts));
- }
- // 交换元素
- public void exchange(int first, int last) {
- int temp = sortInts[first];
- sortInts[first] = sortInts[last];
- sortInts[last] = temp;
- }
1.取数组第一个数为基数,并将数组最后一个数标记为标志数。
2.比较基数右边的数,如果基数大于此数,那么就交换两个数,否则不处理。
3.令基数右边的数为新基数,重复2-3步,直到新基数为标志数为止(此数需执行2-3过程)。
4.取数组第一个数为基数,,将原标志数左边的数标记为新标志数,重复2-4步,直到新标志数为第一个数为止(此数不执行2-4过程)。
其代码如下:
- // 冒泡排序
- public void bubbleSort() {
- for (int i = sortInts.length - 1; i > 0; i--) { // 元素遍历
- for (int j = 0; j < i; j++) { // 元素比较,比i大的已经排好
- if (sortInts[j] > sortInts[j + 1]) // 比较大小,交换
- {
- exchange(j, j + 1);
- }
- }
- }
- }
选择排序是冒泡排序的优化,虽然比较次数上没有改变,但在交换次数上大大减少。其逻辑如下:
1.在数组取第一个数为基数,令标识位等于基数的下标。
2.依次比较基数右边的数,如果此数小于标识位所指向的数,则令标识位等于此数的下标,直到数组最后一个为止(此数也要比较)。
3.交换基数与标志位所指向的数。
4.取基数右边的数为新基数,令标志数等于新基数的下标,重复2-4过程,直到数组倒数第二个数(此数要比较)。
其代码如下:
- // 选择排序
- public void selectSort() {
- for (int i = 0; i < sortInts.length; i++)// 元素遍历
- {
- int temp = i;
- for (int j = i + 1; j < sortInts.length; j++)// 元素比较
- {
- if (sortInts[temp] > sortInts[j])// 比较大小,缓存下标
- {
- temp = j;
- }
- }
- if (temp != i)// 若下标有变,交换
- {
- exchange(i, temp);
- }
- }
- }
1.在数组中取第二个数为基数,令缓冲数等于基数值。
2.依次比较基数左边的数,若此数大于基数,则将此数右移(令此数右边的数等于此数。)直到有数小于基数为值(此数不要移动)。
3.令数组最后右移的数等于缓冲数。
4.取数组第三个数为新基数,令缓冲数等于基数值,重复2-4过程,直到最后一个数(此数需执行243过程)。
其代码如下:
- //插入排序
- public void InsertSort()
- {
- for (int i = 1; i < sortInts.length; i++) //元素遍历
- {
- int temp = sortInts[i];
- int j = i;
- while(j > 0 && temp < sortInts[j-1]) //元素比较,直到比temp小,停止循环
- {
- sortInts[j] = sortInts[j-1];
- j--;
- }
- if( j != i)//若下标有变,交换
- {
- sortInts[j] = temp;//交换停止处元素与sortInts[i]
- }
- }
- }
从上面看,好像插入排序的算法并不比冒泡和选择简单。但是请注意,如果数组局部有序(那怕只有两个数是有序的),情况就大大不同。例如数组{2,3,4,5,6,1,0},数组中2,3,4,5,6属于局部有序。插入排序时,基数为2,3,4,5,6时,都不用处理,当基数为1时,方法只需要移动6次,基数为0时,移动7次。选择排序需要交换7次,冒泡排序需要交换21次,而一次交换至少需要移动2次。
为了测试效率,我们可以添加一些代码,整个类的代码如下:
- import java.util.Arrays;
- import java.util.Random;
- public class SimpleSorts {
- // 排序数组、比较次数、复制次数
- private int[] sortInts;
- private Long compareNum = 0L;
- private Long copyNum = 0L;
- // 初始化sortInts、setter、
- public SimpleSorts(int[] sortInts) {
- this.sortInts = sortInts;
- }
- // getter
- public int[] getSortInts() {
- return sortInts;
- }
- // setter
- public void setSortInts(int[] sortInts) {
- compareNum = 0L;
- copyNum = 0L;
- this.sortInts = sortInts;
- }
- // 显示数组
- public void display() {
- System.out.println("数组:" + Arrays.toString(sortInts));
- }
- // 显示比较信息
- public void displayNum() {
- System.out.println("统计: = 比较 " + compareNum + " 次, 复制 = " + copyNum
- + "次");
- System.out.println();
- }
- // 复制次数
- public void addCopyNum() {
- copyNum++;
- }
- // 比较次数
- public void addCompareNum() {
- compareNum++;
- }
- // 交换元素
- public void exchange(int first, int last) {
- int temp = sortInts[first];
- addCopyNum();
- sortInts[first] = sortInts[last];
- addCopyNum();
- sortInts[last] = temp;
- addCopyNum();
- }
- // 冒泡排序
- public void bubbleSort() {
- for (int i = sortInts.length - 1; i > 0; i--) { // 元素遍历
- for (int j = 0; j < i; j++) { // 元素比较,比i大的已经排好
- if (sortInts[j] > sortInts[j + 1]) // 比较大小,交换
- {
- exchange(j, j + 1);
- }
- addCompareNum();
- }
- }
- }
- // 选择排序
- public void selectSort() {
- for (int i = 0; i < sortInts.length; i++)// 元素遍历
- {
- int temp = i;
- for (int j = i + 1; j < sortInts.length; j++)// 元素比较
- {
- if (sortInts[temp] > sortInts[j])// 比较大小,缓存下标
- {
- temp = j;
- }
- addCompareNum();
- }
- if (temp != i)// 若下标有变,交换
- {
- exchange(i, temp);
- }
- }
- }
- // 插入排序
- public void InsertSort()// 元素遍历
- {
- for (int i = 1; i < sortInts.length; i++) {
- int temp = sortInts[i];
- addCopyNum();
- int j = i;
- addCompareNum();
- while (j > 0 && temp < sortInts[j - 1]) // 元素比较,直到比temp小,停止循环
- {
- if (compareNum != 1) {
- addCompareNum();
- }
- sortInts[j] = sortInts[j - 1];
- addCopyNum();
- j--;
- }
- if (j != i)// 若下标有变,交换
- {
- sortInts[j] = temp;// 交换停止处元素与sortInts[i]
- addCopyNum();
- }
- }
- }
- // 产生随机数组
- public static int[] randomInts(int initNum) {
- int[] ri = new int[initNum];
- for (int i = 0; i < ri.length; i++) {
- Random rd = new Random();
- ri[i] = rd.nextInt(10000);
- }
- return ri;
- }
- // 主方法
- public static void main(String[] args) {
- int[] a = randomInts(1000);
- int[] b = a.clone();
- int[] c = a.clone();
- // 冒泡
- SimpleSorts ss = new SimpleSorts(a);
- ss.bubbleSort();
- ss.displayNum();
- // 选择
- ss.setSortInts(b);
- ss.selectSort();
- ss.displayNum();
- // 插入
- ss.setSortInts(c);
- ss.InsertSort();
- ss.displayNum();
- }
- }
当测试数为10时,结果如下:
- 统计: 比较 = 45 次, 复制 = 66次
- 统计: 比较 = 45 次, 复制 = 24次
- 统计: 比较 = 31 次, 复制 = 36次
当测试数为100时:结果如下:
- 统计: 比较 = 4950 次, 复制 = 6489次
- 统计: 比较 = 4950 次, 复制 = 291次
- 统计: 比较 = 2261 次, 复制 = 2356次
当测试数为1000时:结果如下:
- 统计: 比较 = 499500 次, 复制 = 773589次
- 统计: 比较 = 499500 次, 复制 = 2991次
- 统计: 比较 = 258861 次, 复制 = 259853次
当测试数为10000时:结果如下:
- 统计: = 比较 49995000 次, 复制 = 74298648次
- 统计: = 比较 49995000 次, 复制 = 29979次
- 统计: = 比较 24776215 次, 复制 = 24786200次
参考《Java数据结构和算法》一书,冒泡排序交换和比较操作次数为 N*(N-1)/2,是与N2成正比(记作O(N2));选择排序交换虽然为O(N),但是比较时间与冒泡排序相同,还是O(N2);插入排序比较时间为 N*(N-1)/4。而移到次数与插入次数大致相同,两者近似O(N2),但是如果数据局部有有序,While循环基本为假,则算法所需的时间就能蜕变成O(N)。
简单排序一般适用于小数据量,大数据量排序还得高级排序(如快速排序等)。如果大家想深入研究可以参考《Java数据结构和算法》一书。
- 简单排序的Java实现与效率分析
- 简单排序的Java实现与效率分析
- JAVA之冒泡排序与简单选择排序的实现
- JAVA实现简单的冒泡排序与选择排序
- java String与StringBuffer的效率分析
- 【算法分析与设计】各种排序算法的效率对比
- 几种排序算法的分析与java实现
- 各种排序算法的分析与实现 java
- Java实现简单的排序
- 快速排序方法Java实现与分析
- 插入排序分析与Java实现
- java-归并排序与快排的效率比较
- java实现三种冒号算法的效率分析
- 数据结构与算法分析笔记与总结(java实现)--排序算法的分析
- 排序算法,插入、快速、希尔、基数、归并排序的代码实现和效率分析
- 算法效率的分析--【以选择排序与冒泡排序为基础】
- 一步步学习数据结构和算法之快速排序效率分析及java实现
- 一步步学习数据结构和算法之直接插入排序效率分析及java实现
- 百度图片api
- Why String is immutable or final in Java
- 数据库优化之 数据库不同应用方向优化
- 正则表达式
- ubuntu下eclipse中android模拟器打不开解决
- 简单排序的Java实现与效率分析
- How to create Immutable Class and Object in Java - Tutorial Example
- tomcat无法启动之tj
- build webrtc for android
- 技术人员谈管理之采购管理案例论文
- 非阻塞算法在并发容器中的实现
- Java String Replace Example Tutorial
- Difference between Stack and Heap memory in Java
- How to use ConcurrentHashMap in Java - Example Tutorial and Working