交换排序

冒泡排序

将最后一个元素与倒数第二个元素对比,如果最后一个元素比倒数第二个小,则交换两个元素的位置,再用倒数第二个元素与倒数第三个元数对比,直到比到第一个元素,这样经过第一趟排序后得到第一个最小元素。如此反复几过N(N=length-1)次后可得到排序结果。

Java代码 

packagesort;

importjava.util.Comparator;

/**

* 冒泡排序算法

* @author jzj

* @date 2009-12-9

*

* @param

*/

publicclassBubbleSort>extendsSort {

/**

* 排序算法的实现,对数组中指定的元素进行排序

* @param array 待排序的数组

* @param from 从哪里开始排序

* @param end 排到哪里

* @param c 比较器

*/

publicvoidsort(E[] array,intfrom,intend, Comparator c) {

//需array.length - 1轮比较

for(intk =1; k < end - from +1; k++) {

//每轮循环中从最后一个元素开始向前起泡,直到i=k止,即i等于轮次止

for(inti = end - from; i >= k; i--) {

//按照一种规则(后面元素不能小于前面元素)排序

if(c.compare(array[i], array[i -1]) <0) {

//如果后面元素小于了(当然是大于还是小于要看比较器实现了)前面的元素,则前后交换

swap(array, i, i - 1);

}

}

}

}

/**

* 测试

* @param args

*/

publicstaticvoidmain(String[] args) {

Integer[] intgArr = { 7,2,4,3,12,1,9,6,8,5,11,10};

BubbleSort sort = newBubbleSort();

BubbleSort.testSort(sort, intgArr);

BubbleSort.testSort(sort, null);

}

}

快速排序

快速排序采用了分治法的思想,把大的问题分解为同类型的小问题。 一般分如下步骤: 1)选择一个中枢元素(有很多选法,我的实现里使用第一个元素为中枢的简单方法) 2)以该中枢元素为基准点,将小于中枢的元素放在中枢后集合的前部分,比它大的在集合后部分,待集合基本排序完成后(此时前部分元素小于后部分元素),把中枢元素放在合适的位置。 3)根据中枢元素最后确定的位置,把数组分成三部分,左边的,右边的,枢纽元素自己,对左边的,右边的分别递归调用快速排序算法即可。

这里的重点与难点在于第二步,实现的方式有很多种,我这里实现了三种。 第一种实现(partition1方法): 以第一个元素为中枢元素,在中枢元素后面集合中从前往后寻找第一个比中枢元素小的元素,并与第一个元素交换,然后从剩余的元素中寻找第二个比中枢元素小的 元素,并与第二位元素交换,这样直到所有小于中枢元素找完为止,并记下最后一次放置小于中枢的元素位置minIndex(即小于中枢与大于中枢的分界), 并将中枢元素与minIndex位置元素互换,然后对中枢元素两边的序列进行同样的操作。 此种实现最为简洁,处理过程中不需要把中枢元素移来移去,只是在其它元素完成基本排序后(前部分小于后部分元素)再把中枢元素放置到适当的位置

第二种实现(partition2方法): 以第一个元素为中枢元素,刚开始时使用低指针指向中枢元素。当中枢元素在低指针位置时,此时我们判断高指针指向的元素是否小于中枢元素,如果大于中枢元素 则高指针继续向头移动,如果小于则与中枢元素交换,此时中枢元素被移到了高指针位置;当中枢元素在高指针位置时,我们此时判断低指针指向的元素是否大于中 枢元素,如果小于中枢元素则低指针继续向尾移动,如果大于则与中枢元素交换,此时中枢元素又回到了低指针位置;这时是拿高还是低指针所指向的元素与中枢比 较时根据前面逻辑来处理,直到高低指针指向同一位置则完成一轮排序,然后再对中枢元素两边的序列进行同样的操作直到排序完成 此种实现逻辑比较好理解,中枢元素的永远在低指针或指针所指向的位置,每次找到需处理的元 素后,要与中枢交换,中枢就像皮球一样从这里踢到那里,又从那里踢到这里。但此种实现会频繁地交换中枢元素,性能可能不如第一种

第三种实现(partition3方法): 此种方式与前两种方式不太一样,同时移动高低指针,低指针向尾找出大于等于中枢的元素,而高向头找出小于中枢的元素,待两者都找出后交换高低指针所指向的 元素,直到高低指针指向同一位置止,然后比较中枢与高低指针所指向的元素大小,如果中枢元素大,则直接与高低指针元素交换,如果中枢元素小于等于高低指针 元素,则中枢元素与高低指针前一元素交换,完成一轮比较,然后再对中枢元素两边的序列进行同样的操作直到排序完成

此种方式有点难度,在移动元素时要注意的是:与中枢相等的元素也要向集合后部移动,不然的话如[3,3,0,3,3]第一轮排序结果不准确,虽然最后结果 正确。当中枢后面的元素集合移动完成后,还得要把中枢元素放置在集合中的合适位置,这就需要找准集合中前部分与后部分的边界,最后只能把中枢元素与最后一 个小于中枢的元素进位置互换。但此种实现方式与第一种有点像,也不需要把中枢元素调来调去的,而是待后面集合排序完成后将中枢放入适当位置

Java代码 

packagesort;

importjava.util.Arrays;

importjava.util.Comparator;

/**

* 快速排序算法

* @author jzj

* @date 2009-12-9

*

* @param

*/

publicclassQuickSort>extendsSort {

/**

* 排序算法的实现,对数组中指定的元素进行排序

* @param array 待排序的数组

* @param from 从哪里开始排序

* @param end 排到哪里

* @param c 比较器

*/

publicvoidsort(E[] array,intfrom,intend, Comparator c) {

quickSort(array, from, end, c);

}

/**

* 递归快速排序实现

* @param array 待排序数组

* @param low 低指针

* @param high 高指针

* @param c 比较器

*/

privatevoidquickSort(E[] array,intlow,inthigh, Comparator c) {

/*

* 如果分区中的低指针小于高指针时循环;如果low=higth说明数组只有一个元素,无需再处理;

* 如果low > higth,则说明上次枢纽元素的位置pivot就是low或者是higth,此种情况

* 下分区不存,也不需处理

*/

if(low < high) {

//对分区进行排序整理

intpivot = partition1(array, low, high, c);

/*

* 以pivot为边界,把数组分成三部分[low, pivot - 1]、[pivot]、[pivot + 1, high]

* 其中[pivot]为枢纽元素,不需处理,再对[low, pivot - 1]与[pivot + 1, high]

* 各自进行分区排序整理与进一步分区

*/

quickSort(array, low, pivot - 1, c);

quickSort(array, pivot + 1, high, c);

}

}

/**

* 实现一

*

* @param array 待排序数组

* @param low 低指针

* @param high 高指针

* @param c 比较器

* @return int 调整后中枢位置

*/

privateintpartition1(E[] array,intlow,inthigh, Comparator c) {

E pivotElem = array[low];//以第一个元素为中枢元素

//从前向后依次指向比中枢元素小的元素,刚开始时指向中枢,也是小于与大小中枢的元素的分界点

intborder = low;

/*

* 在中枢元素后面的元素中查找小于中枢元素的所有元素,并依次从第二个位置从前往后存放

* 注,这里最好使用i来移动,如果直接移动low的话,最后不知道数组的边界了,但后面需要

* 知道数组的边界

*/

for(inti = low +1; i <= high; i++) {

//如果找到一个比中枢元素小的元素

if(c.compare(array[i], pivotElem) <0) {

swap(array, ++border, i);//border前移,表示有小于中枢元素的元素

}

}

/*

* 如果border没有移动时说明说明后面的元素都比中枢元素要大,border与low相等,此时是

* 同一位置交换,是否交换都没关系;当border移到了high时说明所有元素都小于中枢元素,此

* 时将中枢元素与最后一个元素交换即可,即low与high进行交换,大的中枢元素移到了 序列最

* 后;如果 low

* 中枢元素,此时中枢元素与前部分数组中最后一个小于它的元素交换位置,使得中枢元素放置在

* 正确的位置

*/

swap(array, border, low);

returnborder;

}

/**

* 实现二

*

* @param array 待排序数组

* @param low 待排序区低指针

* @param high 待排序区高指针

* @param c 比较器

* @return int 调整后中枢位置

*/

privateintpartition2(E[] array,intlow,inthigh, Comparator c) {

intpivot = low;//中枢元素位置,我们以第一个元素为中枢元素

//退出条件这里只可能是 low = high

while(true) {

if(pivot != high) {//如果中枢元素在低指针位置时,我们移动高指针

//如果高指针元素小于中枢元素时,则与中枢元素交换

if(c.compare(array[high], array[pivot]) <0) {

swap(array, high, pivot);

//交换后中枢元素在高指针位置了

pivot = high;

} else{//如果未找到小于中枢元素,则高指针前移继续找

high--;

}

} else{//否则中枢元素在高指针位置

//如果低指针元素大于中枢元素时,则与中枢元素交换

if(c.compare(array[low], array[pivot]) >0) {

swap(array, low, pivot);

//交换后中枢元素在低指针位置了

pivot = low;

} else{//如果未找到大于中枢元素,则低指针后移继续找

low++;

}

}

if(low == high) {

break;

}

}

//返回中枢元素所在位置,以便下次分区

returnpivot;

}

/**

* 实现三

*

* @param array 待排序数组

* @param low 待排序区低指针

* @param high 待排序区高指针

* @param c 比较器

* @return int 调整后中枢位置

*/

privateintpartition3(E[] array,intlow,inthigh, Comparator c) {

intpivot = low;//中枢元素位置,我们以第一个元素为中枢元素

low++;

//----调整高低指针所指向的元素顺序,把小于中枢元素的移到前部分,大于中枢元素的移到后面部分

//退出条件这里只可能是 low = high

while(true) {

//如果高指针未超出低指针

while(low < high) {

//如果低指针指向的元素大于或等于中枢元素时表示找到了,退出,注:等于时也要后移

if(c.compare(array[low], array[pivot]) >=0) {

break;

} else{//如果低指针指向的元素小于中枢元素时继续找

low++;

}

}

while(high > low) {

//如果高指针指向的元素小于中枢元素时表示找到,退出

if(c.compare(array[high], array[pivot]) <0) {

break;

} else{//如果高指针指向的元素大于中枢元素时继续找

high--;

}

}

//退出上面循环时 low = high

if(low == high) {

break;

}

swap(array, low, high);

}

//----高低指针所指向的元素排序完成后,还得要把中枢元素放到适当的位置

if(c.compare(array[pivot], array[low]) >0) {

//如果退出循环时中枢元素大于了低指针或高指针元素时,中枢元素需与low元素交换

swap(array, low, pivot);

pivot = low;

} elseif(c.compare(array[pivot], array[low]) <=0) {

swap(array, low - 1, pivot);

pivot = low - 1;

}

//返回中枢元素所在位置,以便下次分区

returnpivot;

}

/**

* 测试

* @param args

*/

publicstaticvoidmain(String[] args) {

Integer[] intgArr = { 3,1,1,1,1,1,1};

QuickSort sort = newQuickSort();

QuickSort.testSort(sort, intgArr);

QuickSort.testSort(sort, null);

}

}

归并排序

Java代码 

packagesort;

importjava.lang.reflect.Array;

importjava.util.Comparator;

/**

* 归并排序算法

* @author jzj

* @date 2009-12-11

*

* @param

*/

publicclassMergeSort>extendsSort {

/**

* 排序算法的实现,对数组中指定的元素进行排序

* @param array 待排序的数组

* @param from 从哪里开始排序

* @param end 排到哪里

* @param c 比较器

*/

publicvoidsort(E[] arr,intfrom,intend, Comparator c) {

partition(arr, from, end, c);

}

/**

* 递归划分数组

* @param arr

* @param from

* @param end

* @param c void

*/

privatevoidpartition(E[] arr,intfrom,intend, Comparator c) {

//划分到数组只有一个元素时才不进行再划分

if(from < end) {

//从中间划分成两个数组

intmid = (from + end) /2;

partition(arr, from, mid, c);

partition(arr, mid + 1, end, c);

//合并划分后的两个数组

merge(arr, from, end, mid, c);

}

}

/**

* 数组合并,合并过程中对两部分数组进行排序

* 前后两部分数组里是有序的

* @param arr

* @param from

* @param end

* @param mid

* @param c void

*/

privatevoidmerge(E[] arr,intfrom,intend,intmid, Comparator c) {

E[] tmpArr = (E[]) Array.newInstance(arr[0].getClass(), end - from +1);

inttmpArrIndex =0;//指向临时数组

intpart1ArrIndex = from;//指向第一部分数组

intpart2ArrIndex = mid +1;//指向第二部分数组

//由于两部分数组里是有序的,所以每部分可以从第一个元素依次取到最后一个元素,再对两部分

//取出的元素进行比较。只要某部分数组元素取完后,退出循环

while((part1ArrIndex <= mid) && (part2ArrIndex <= end)) {

//从两部分数组里各取一个进行比较,取最小一个并放入临时数组中

if(c.compare(arr[part1ArrIndex], arr[part2ArrIndex]) <0) {

//如果第一部分数组元素小,则将第一部分数组元素放入临时数组中,并且临时数组指针

//tmpArrIndex下移一个以做好下次存储位置准备,前部分数组指针part1ArrIndex

//也要下移一个以便下次取出下一个元素与后部分数组元素比较

tmpArr[tmpArrIndex++] = arr[part1ArrIndex++];

} else{

//如果第二部分数组元素小,则将第二部分数组元素放入临时数组中

tmpArr[tmpArrIndex++] = arr[part2ArrIndex++];

}

}

//由于退出循环后,两部分数组中可能有一个数组元素还未处理完,所以需要额外的处理,当然不可

//能两部分数组都有未处理完的元素,所以下面两个循环最多只有一个会执行,并且都是大于已放入

//临时数组中的元素

while(part1ArrIndex <= mid) {

tmpArr[tmpArrIndex++] = arr[part1ArrIndex++];

}

while(part2ArrIndex <= end) {

tmpArr[tmpArrIndex++] = arr[part2ArrIndex++];

}

//最后把临时数组拷贝到源数组相同的位置

System.arraycopy(tmpArr, 0, arr, from, end - from +1);

}

/**

* 测试

* @param args

*/

publicstaticvoidmain(String[] args) {

Integer[] intgArr = { 5,9,1,4,1,2,6,3,8,0,7};

MergeSort insertSort = newMergeSort();

Sort.testSort(insertSort, intgArr);

Sort.testSort(insertSort, null);

}

}

基数排序

基数排序的主要思路是,将所有待比较数值(注意,必须是正整数)统一为同样的数位长度,数位较短的数前面补零. 然后, 从最低位开始, 依次进行一次稳定排序.这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列.

它的理论比较容易理解,但实现却有一点绕。

Java代码 

packagesort;

importjava.util.Arrays;

publicclassRadixSort {

/**

* 取数x上的第d位数字

* @param x 数

* @param d 第几位,从低位到高位

* @return

*/

publicintdigit(longx,longd) {

longpow =1;

while(--d >0) {

pow *= 10;

}

return(int) (x / pow %10);

}

/**

* 基数排序实现,以升序排序(下面程序中的位记录器count中,从第0个元素到第9个元素依次用来

* 记录当前比较位是0的有多少个..是9的有多少个数,而降序时则从第0个元素到第9个元素依次用来

* 记录当前比较位是9的有多少个..是0的有多少个数)

* @param arr 待排序数组

* @param digit 数组中最大数的位数

* @return

*/

publiclong[] radixSortAsc(long[] arr) {

//从低位往高位循环

for(intd =1; d <= getMax(arr); d++) {

//临时数组,用来存放排序过程中的数据

long[] tmpArray =newlong[arr.length];

//位记数器,从第0个元素到第9个元素依次用来记录当前比较位是0的有多少个..是9的有多少个数

int[] count =newint[10];

//开始统计0有多少个,并存储在第0位,再统计1有多少个,并存储在第1位..依次统计到9有多少个

for(inti =0; i < arr.length; i++) {

count[digit(arr[i], d)] += 1;

}

/*

* 比如某次经过上面统计后结果为:[0, 2, 3, 3, 0, 0, 0, 0, 0, 0]则经过下面计算后 结果为:

* [0, 2, 5, 8, 8, 8, 8, 8, 8, 8]但实质上只有如下[0, 2, 5, 8, 0, 0, 0, 0, 0, 0]中

* 非零数才用到,因为其他位不存在,它们分别表示如下:2表示比较位为1的元素可以存放在索引为1、0的

* 位置,5表示比较位为2的元素可以存放在4、3、2三个(5-2=3)位置,8表示比较位为3的元素可以存放在

* 7、6、5三个(8-5=3)位置

*/

for(inti =1; i <10; i++) {

count[i] += count[i - 1];

}

/*

* 注,这里只能从数组后往前循环,因为排序时还需保持以前的已排序好的 顺序,不应该打

* 乱原来已排好的序,如果从前往后处理,则会把原来在前面会摆到后面去,因为在处理某个

* 元素的位置时,位记数器是从大到到小(count[digit(arr[i], d)]--)的方式来处

* 理的,即先存放索引大的元素,再存放索引小的元素,所以需从最后一个元素开始处理。

* 如有这样的一个序列[212,213,312],如果按照从第一个元素开始循环的话,经过第一轮

* 后(个位)排序后,得到这样一个序列[312,212,213],第一次好像没什么问题,但问题会

* 从第二轮开始出现,第二轮排序后,会得到[213,212,312],这样个位为3的元素本应该

* 放在最后,但经过第二轮后却排在了前面了,所以出现了问题

*/

for(inti = arr.length -1; i >=0; i--) {//只能从最后一个元素往前处理

//for (int i = 0; i < arr.length; i++) {//不能从第一个元素开始循环

tmpArray[count[digit(arr[i], d)] - 1] = arr[i];

count[digit(arr[i], d)]--;

}

System.arraycopy(tmpArray, 0, arr,0, tmpArray.length);

}

returnarr;

}

/**

* 基数排序实现,以降序排序(下面程序中的位记录器count中,从第0个元素到第9个元素依次用来

* 记录当前比较位是0的有多少个..是9的有多少个数,而降序时则从第0个元素到第9个元素依次用来

* 记录当前比较位是9的有多少个..是0的有多少个数)

* @param arr 待排序数组

* @return

*/

publiclong[] radixSortDesc(long[] arr) {

for(intd =1; d <= getMax(arr); d++) {

long[] tmpArray =newlong[arr.length];

//位记数器,从第0个元素到第9个元素依次用来记录当前比较位是9的有多少个..是0的有多少个数

int[] count =newint[10];

//开始统计0有多少个,并存储在第9位,再统计1有多少个,并存储在第8位..依次统计

//到9有多少个,并存储在第0位

for(inti =0; i < arr.length; i++) {

count[9- digit(arr[i], d)] +=1;

}

for(inti =1; i <10; i++) {

count[i] += count[i - 1];

}

for(inti = arr.length -1; i >=0; i--) {

tmpArray[count[9- digit(arr[i], d)] -1] = arr[i];

count[9- digit(arr[i], d)]--;

}

System.arraycopy(tmpArray, 0, arr,0, tmpArray.length);

}

returnarr;

}

privateintgetMax(long[] array) {

intmaxlIndex =0;

for(intj =1; j < array.length; j++) {

if(array[j] > array[maxlIndex]) {

maxlIndex = j;

}

}

returnString.valueOf(array[maxlIndex]).length();

}

publicstaticvoidmain(String[] args) {

long[] ary =newlong[] {123,321,132,212,213,312,21,223};

RadixSort rs = newRadixSort();

System.out.println("升 - "+ Arrays.toString(rs.radixSortAsc(ary)));

ary = newlong[] {123,321,132,212,213,312,21,223};

System.out.println("降 - "+ Arrays.toString(rs.radixSortDesc(ary)));

}

}

时间复杂度与空间复杂度对比表

原文:http://jiangzhengjun.iteye.com/blog/547735

java常见的算法_Java常用算法总结(转)相关推荐

  1. Java常见的几种排序算法-插入、选择、冒泡、快排、堆排等

    本文就是介绍一些常见的排序算法.排序是一个非常常见的应用场景,很多时候,我们需要根据自己需要排序的数据类型,来自定义排序算法,但是,在这里,我们只介绍这些基础排序算法,包括:插入排序.选择排序.冒泡排 ...

  2. java g1 详解_JAVA垃圾收集算法总结以及CMS、G1算法详解

    前段时间由于工作原因一直很忙,上周项目验收后时间终于空闲下来,博客也有好几个月没有更新了,趁着还有几天放假,借这个机会写点东西:网上也有很多人写过Java垃圾收集器,特别现在主流比较火的CMS和G1算 ...

  3. 【数据结构与算法】常用算法

    五大常用算法 分治 动态规划 最优子结构 边界 状态转移函数 爬楼梯问题: 4. 最优子结构 F(10)的最优子结构为F(9)和F(8) 5. 边界 F(1) = 1 F(2) = 2 6. 状态转移 ...

  4. java开发过程中几种常用算法

    排序算法 排序算法中包括:简单排序.高级排序 简单排序 简单排序常用的有:冒泡排序.选择排序.插入排序 冒泡排序代码如下: 1 private static void bubbleSrot(int[] ...

  5. java经典50题_JAVA经典算法50题(3)【面试+工作】

    原标题:JAVA经典算法50题(3)[面试+工作] JAVA经典算法50题(3)[面试+工作] [程序21] 题目:求1+2!+3!+...+20!的和. 1.程序分析:此程序只是把累加变成了累乘. ...

  6. Java排序算快速排序_Java排序算法 [快速排序]

    package cn.com.dom4j.sort; public class QuickSort { /** 快速排序 在 Java中, 快速排序被用作基本数据类型的排序 (当然, 不只快速排序一种 ...

  7. java选择排序代码_Java排序算法总结之选择排序

    本文实例讲述了Java排序算法总结之选择排序.分享给大家供大家参考.具体分析如下: 选择排序的基本操作就是每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部 ...

  8. java基础之算法_java基础算法

    package com.sxwl; import org.springframework.boot.SpringApplication; import org.springframework.boot ...

  9. java程序两点之间最短路径算法_java 最短路径算法 如何实现有向 任意两点的最短路径...

    展开全部 Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,用于计算一个节点到其他所有节e68a8462616964757a686964616f31333361316131点的最短路径.主要 ...

最新文章

  1. python多进程优化_『Python』多进程处理
  2. matlab导出jar包错误Error: An error occurred while shelling out to javac(erro code = 1)解决办法...
  3. linux 软硬文件类型,linux文件属性和类型、系统链接文件、软链接和硬链接
  4. C# 设置Word文档中图片的大小
  5. SQLServer游标简单应用(求分组最小值问题)
  6. CentOS上搭建Nginx + Mono 运行 asp.net
  7. paper reading in this week
  8. 深入浅出强化学习_皋兰县举办科级干部学习贯彻党的十九届五中全会精神培训班...
  9. ​苏宁回应股权质押给淘宝:正常合作;苹果App Store被越狱商店指控垄断;Docker 20.10.0发布|极客日报...
  10. GDAL读取S-57海图数据中文属性值乱码问题解决
  11. 新年快乐@2008!
  12. N9(Meego系统)删除自带软件方法------笔者亲测,可行,无副作用
  13. 虚拟机中标麒麟操作系统gcc安装
  14. 在线地图地址3857+4326
  15. 大压缩文件解压错误,台服wow common-2.MPQ 文件损坏
  16. MEION:锁相环锁定状态仿真与板载测试情况分析
  17. linux 机器无法访问网络
  18. Python ORM框架peewee
  19. 读论文:Self-Attention ConvLSTM for Spatiotemporal Prediction
  20. vue中循环图片不显示问题

热门文章

  1. 3DSlicer15:Scripted Module
  2. 让iis支持下载apk,ipa文件
  3. Asp.net常用优化方法
  4. Delphi中的各种路径
  5. 三个很有用的sqlserver中的处理多个以分隔符分隔的参数的函数
  6. linux编程:getenv,putenv,setenv
  7. layui动态生成的下拉框被遮住
  8. 操作系统(一)操作系统的概念、功能
  9. 【译】Making Sense of Ethereum’s Layer 2 Scaling Solutions: State Channels, Plasma, and Truebit
  10. 10 Lessons Learned Doing ICOs