一.冒泡排序
特点:实现简单,无额外空间消耗,速度较慢,适合数据较少的场景,复杂度为O(N^2)
思路:每一轮比较都从头开始,然后两两比较,如果左值比右值大,则交换位置,每一轮结束后,当前轮"最后一个元素"必将是最大的.
场景:算法稳定,数据量较小的场景。时间复杂度O(n^2)
原始数组:[4,3,10,6,2] 过程:每一次遍历,都会将“无序区”中最大的元素交换到数组的末尾 ------------> -->3,4,10,6,2 -->3,4,10,6,2 -->3,4,6,10,2 -->3,4,6,2,[10] ------------> -->3,4,6,2,[10] -->3,4,6,2,[10] -->3,4,2,[6,10] ------------> -->3,4,2,[6,10] -->3,2,[4,6,10] ------------> -->2,[3,4,6,10] ----> 结束:[2,3,4,6,10]
public class BubbleSort { static void sort(int[] sources){ int tmp; int size = sources.length; for(int i =0; i < size - 1; i++){ //精髓:每次遍历,都将"最大"元素顶到最后 //0, 1,8,13,3,4,7,||20 //0, 1,8,3,4,7,|| 13,20 //0, 1,3,4,7,||8,13,20 //0 ,1,3,4|| 7,8,13,20 for(int j=0; j< size -i -1;j++){ if(sources[j] > sources[j+1]){ tmp = sources[j]; sources[j] = sources[j+1]; sources[j+1] = tmp; } } } } /** * @param args */ public static void main(String[] args) { int[] sources = {1,0,20,8,13,3,4,7}; sort(sources); System.out.println(Arrays.toString(sources)); } }
二.快速排序
特点:速度快,无额外空间开支,不过算法本身基于递归,可能对内存有额外的消耗.不适合数据集合较大的场景.
思路:就像对班级中的同学根据身高分组一样,首先找个学生做"标杆",比他高的站后面,比他矮的站前面;然后从此"标杆"之前/之后的队列中,分别再在找一个"标杆",并按照相同的规则排队,直到结束!!"标杆"的选取,可以是随机的.下面的例子中,将指定数组"区间"(low~high)的一个元素(即low)作为"标杆".
场景:算法不稳定,时间复杂度O(n*logn),空间复杂度O(n*logn)
原始数组:[4,3,10,6,2] 过程:每次递归内的排序,总是先选择“标杆”,我们取递归区间的第一个元素为标杆 ------------> --->标杆为4,右边开始交换,将比4小的交换 --->2,3,10,6,[4] --->标杆为4,左边开始交换,将比4大的交换 --->2,3,[4],6,10 ------------> ---->[4]的左右两边分别递归,分成2部分 (递归1),标杆为2 ---->2,[3] (递归2),标杆为6 ---->[6],10 .... 结束:[2,3,4,6,10]
public class QuickSort { public static void sort(int[] sources,int low,int high){ if(low < high){ int key = sources[low];//此轮比较的key,左边比key大,右边比key小. int l = low; int h = high; int tmp; while(l < h){ //因为我们不能创建额外的数组,所以才取了"交换"数据的方式. //从右边开始,将比key大的交换到过来. while(l < h && sources[h] >= key){ h--; } //右边找到了比key大的. if(l < h){ //交换顺序 tmp = sources[l]; sources[l] = sources[h]; sources[h] = tmp; } //从左边开始,将比key小的交换过来 while(l < h && sources[l] <= key){ l++; } if(l < h){ tmp = sources[l]; sources[l] = sources[h]; sources[h] = tmp; } } sort(sources, low, l-1); sort(sources, l+1, high); } } /** * @param args */ public static void main(String[] args) { int[] sources = {2,15,3,100,87,-1,34,25,77,80,62,11,7,2,55,22}; sort(sources, 0, sources.length -1); System.out.println(Arrays.toString(sources)); } }
三.归并排序
特点: 速度快,不过需要额外的一些存储空间(存储当前递归中有序区),内部基于递归,不适合数据量较大的场景.
思路:分治法,将数组逐步拆分为"组",直到最小的"组",然后每个组内排序,然后依次和相邻的组"排序合并",其中"排序".其内部排序非常简单.直接比较.
场景:算法稳定,适合元素个数较多时,时间复杂度O(n*logn),空间复杂度O(1)
原始数组:[4,3,10,6,2] 过程:首先将原始数组拆分为更小的组,然后一次对“组”进行排序 ------------> --->拆分 [4,3,10,6,2] | [4,3] [10,6,2] | | [4],[3] [10,6],[2] | | [4],[3] [10],[6],[2] --->合并与排序,从底部开始(递归中) [4],[3] [10],[6],[2] | | [3,4] [6,10],[2] | | [3,4] [2,6,10] | [2,3,4,6,10] .... 结束:[2,3,4,6,10]
public class MergeSort { /** * 对指定区间的数据进行排序,将begin~end之间的数据分成两部分 * @param sources * @param begin * @param end */ public static void sort(int[] sources,int begin,int end){ if(begin < end){ int range = end - begin; int mid = begin + range/2; sort(sources,begin,mid);//左段 sort(sources,mid + 1,end);//右端 merge(sources, begin, mid, end); } } /** * 对begin~mid,mid+1 ~end两段区间中的数据进行排序并合并 * @param sources * @param begin * @param mid * @param end */ private static void merge(int[] sources,int begin,int mid,int end){ int[] tmp = new int[end - begin + 1]; int b1 = begin; int e1 = mid; int b2 = mid+1; int e2 = end; int i=0; for(;b1 <= e1 && b2 <= e2 ; i++){ //填充tmp数组,并依此在两段数据区域中找到最小的 if(sources[b1] <= sources[b2]){ tmp[i] = sources[b1]; b1++; }else{ tmp[i] = sources[b2]; b2++; } } //到此为止,两段数据区域,已经至少一个被扫描完毕 if(b1 > e1){ //如果b1~e1扫描完毕,那么可能b2~e2还有剩余 for(int t = b2;t < e2 + 1; t++){ tmp[i] = sources[t]; i++; } } if(b2 > e2){ //如果b2~e2扫描完毕,那么可能b1~e1还有剩余 for(int t = b1;t < e1 + 1; t++){ tmp[i] = sources[t]; i++; } } //replace and fill:将tmp数组的数据,替换到source中,begin~end //因为此时tmp中的数据是排序好的 i=0; for(int t= begin;t <= end; t++){ sources[t] = tmp[i]; i++; } tmp = null;// } /** * @param args */ public static void main(String[] args) { int[] sources = {1,0,20,8,13,3,4,7,-1}; sort(sources,0,sources.length -1 ); System.out.println(Arrays.toString(sources)); } }
四.堆排序
特点:速度快,适合大数据量排序,无额外空间消耗,
思路: 将原始数据看做一个"二叉树",首先构建一个"大顶堆":从最后一个(层)非叶子节点开始倒序遍历整个树,依次比较当前节点和它的左右子节点的大小,将较大的值和当前节点交换,树遍历结束后,那么树的根(堆顶)肯定是数组中最大的元素.这个过程称为"构建初始堆".
当"初始堆"构建完毕,最大的元素放在了"堆顶",将"堆顶"的元素和数组的最后一个元素交换,由此可见,数组的最后元素在此后的排序中,已经不需要参与了.那么剩余的元素集合,就是"无序区域".
接下来,对"无序区域"的排序方式和构建"初始堆"过程一样.直到整个"树"被遍历结束.
场景:算法不稳定,适合元素个数较多时,时间复杂度O(n*logn),空间复杂度O(1)
原始数组:[4,3,10,6,2,1] 过程:首先构建一次“初始堆”,然后基于“初始堆”进行“交换” ------------->按照元素顺序,构建成树 [4] | | [3] [10] | | [6] [2] [1] -------------->初始堆,从树的叶子节点开始向上进行,最终需要将最大的元素,交换到“顶”部 -------------->每个节点都和其左右子节点进行比较,将最大的元素,和当前节点交换,如果交换过程中,有打破"大顶堆"原则,将递归. ++++++++++++++ [4] | | [6] [10] | | [3] [2] [1] 因为[6],[3],[2]中,6最大,因此6需要和3交换位置。至此,[3],[10]两个节点已经肃清 ++++++++++++++ [10] | | [6] [4] | | [3] [2] [1] 因为在[4],[6],[10]中,10最大,因此4需要和10交换位置;此过程依次进行,直到根节点。 到此为止数组为[10,6,4,3,2,1],全部为“无序区” ---------------->交换与排序 将堆顶的元素与“无序区”中最后一个元素交换,“1,6,4,3,2,[10]”,其中[10]为有序区,[10]之前的为“无序区” 此后,有序区,将不再参与“堆顶”元素的交换,为了便于理解,在下图中,我们暂且将“有序区”中的元素移除树 ++++++++++++++ [1] | | [6] [4] | [3] [2] 接下来,和“初始堆”的过程一样:从树的底部往上,比较节点,最大元素放在“顶部”,并将其交换到“有序区” ++++++++++++++ [6] | | [1] [4] | [3] [2] ++++++++++++++因为1调换位置后,[1][3][2]不满足大顶堆,递归 [6] | | [3] [4] | [1] [2] ++++++++++++++(6交换到有序区,即[6]和最底层叶子节点[2]交换) [2] | | [1] [4] | [3] ++++++++++++++(继续调整堆顶,基于交换原则,[2]和[4]交换) [4] | | [3] [2] | [1] ++++++++++++++(4交换到有序区,即[4]与最底层叶子节点[1]交换) [1] | [3] [2] ..... 最终数组为:[1,2,3,4,6,10]
public class MaxHeapSort { public static void sort(int[] sources,int length){ //堆将会以"二叉树"的方式构建,在逻辑上,需要确保"左右"两边树高一致. int i = length/2; //首先构建一次"初始堆",从树的叶子节点"倒序"遍历所有的节点 //此次的目的,就是将整棵树中,值最大的节点,交换到树的根部. int max = length - 1;//最大索引 for(; i>=0; i--){ heap(sources,i,max); } //"交换"位置,每循环一次,都会把当前树的"根"(也是最大值)和"当前无序区域"的最后一个位置交换 //交换之后,最后一个位置是最大值,此位置之前的节点,为"无序区域". //每执行一次heap方法,都会将当前"无序区域"的最大值放在"根"部. //每交换一次,"无序区域"的长度-1(因为最大值已经产生,并交换到了当前"区域"的尾部,下一次heap,就不需要参与) for(i = max; i>= 1;i--){ int tmp = sources[0]; sources[0] = sources[i]; sources[i] = tmp; max--;//将source[max]"移动"到有序区,将不再参与此后的heap过程 heap(sources, 0, max);//从"堆顶"调整,每次只需比较最上层2个节点 } } /** * * @param sources 原始数组 * @param i 当前节点位置 * @param max (需要比较的范围,即剩余的无序数组的最大索引) */ private static void heap(int[] sources,int i,int max){ //计算出当前"节点i"的左右子节点的位置(在数组中的位置) int l = 2 * i + 1;//左 int r = 2 * i + 2;//右 int c = i;//当前索引 //找出"当前节点""左右子节点"三个节点中,最大的值,以构建"大顶堆" if(l <= max && sources[l] > sources[c]){ c = l; } if(r <= max && sources[r] > sources[c]){ c = r; } if(c != i){ //交换数据 int tmp = sources[i]; sources[i] = sources[c]; sources[c] = tmp; heap(sources, c, max);//每次交换,重新调整,满足"大顶堆"要求 } } /** * @param args */ public static void main(String[] args) { int[] sources = {11,0,20,8,13,3,4,7}; sort(sources,sources.length); System.out.println(Arrays.toString(sources)); } }
五.选择排序/交换排序
特点:每次遍历"无序区域"时,找到一个最小的值,并和"无序区域"的第一个元素交换位置,至此"无序区域"的剩余元素,继续执行上述遍历过程..它和"冒泡排序"异曲同工.【从无序区中“选择”出最小的元素,交换到“无序区”的头部】
场景:算法不稳定,元素个数较小时,时间复杂度O(n^2),空间复杂度O(1)
原始数组:[4,3,10,6,2,1] 过程:将数组分为“有序区”,“无序区”,每次遍历都从“无序区”找到最小的元素“交换”到“有序区”的最前面 ------------->[]4,3,10,6,2,1;初始时有序区为空(实现有所差异) ---->[1],4,3,10,6,2 当前无序区中,1为最小,那么把1放在“无序区”的最前面,我们也可以认为1位于有序区的最后面 ---->[1,2],4,3,10,6 将2放在“无序区”的最前面,也可以认为为“有序区”的最后面 ---->[1,2,3]4,10,6 ---->[1,2,3,4],10,6 ---->[1,2,3,4,6],10 ....
public class SelectSort { public static void sort(int[] sources){ int length = sources.length; int n; for(int i=0; i < length -1; i++){ n = i; for(int j= i+1; j< length; j++){ if(sources[j] < sources[i]){ n = j; } } if(n != i){ int tmp = sources[i]; sources[i] = sources[n]; sources[n] = tmp; } } } /** * @param args */ public static void main(String[] args) { int[] sources = {2,15,3,100,87,-1,34,25,77,80,62,11,7,2,55,22}; sort(sources); System.out.println(Arrays.toString(sources)); } }
六.插入排序:
特点:和冒泡排序很像,"有序区域"在数组的前部,依次遍历"无序区域"中的元素,并将"无序区域"中的第一个元素,和"有序区域"中的元素比较(从后往前),并将此元素不断向前"推进".它和“选择排序”也很相似。[依次将无序区中的元素“插入”到有序区中]
场景:算法稳定,元素格式较小时,时间复杂度O(n^2),空间复杂度O(1)
原始数组:[4,3,10,6,2,1] 过程:和“选择排序”很像,只不过“无序区”中的元素是和“有序区”比较(选择排序,是从无序区中“选择”最小的,放入有序区),然后一次在“有序区”中交换位置。 ------------->[4],3,10,6,2,1;初始时有序区为空也可以为第一个元素(实现有所差异) ---->[3,4],10,6,2,1 首先将无序区中的3,和有序区中的4比较,并交换位置,此时3进入有序区 ---->[3,4,10],6,2,1 将10与[3,4]从后往前比较,并交换位置 ---->[3,4,6,10],2,1 ---->[2,3,4,6,10],1 ....
public class InsertSort { public static void sort(int[] sources){ int length = sources.length; int n; for(int i = 1; i < length; i++){ n = i - 1; int cv = sources[i];//当前需要比较的元素 //依次遍历此元素所在位置之前的元素集合(此集合为已排序的集合) while(n >=0 && cv < sources[n]){ //如果当前元素,比"已排序集合"的元素值小 //往前交换位置,类似于"冒泡" sources[n+1] = sources[n]; sources[n] = cv; n--; } } } /** * @param args */ public static void main(String[] args) { int[] sources = {0,2,15,3,100,87,-1,34}; sort(sources); System.out.println(Arrays.toString(sources)); } }
七.希尔排序
特点:"列排序",将数组数据,在逻辑上分成“多个列”,然后每一列排序。每次遍历成功后,列数减半,继续排序,直到最后为一列时,进行一次插入排序。速度比“插入排序”要快,因为减少了元素交换的次数,是“插入排序”的改进版本。
场景:算法不稳定,元素个数较小时,时间复杂度O(n*logn),空间复杂度O(n^s),其中s为组数。
原始数组:[4,3,10,6,2,1,8,5] 过程:"列"排序,依次将数组,分为N个列(length/2),然后对每一列进行排序。直到最后列数为1.(每次排序之后,列数减半) ------------>8个元素,分为4列 4,3,10,6 2,1,8,5 ----->对每一列进行排序(竖向) 2,1,8,5 4,3,10,6 此时数组为[2,1,8,5,4,3,10,6] ----->然后分为2列(4列变为2列,列数减半) 2,1 8,5 4,3 10,6 ----->排序 2,1 4,3 8,5 10,6 此时数组为[2,1,4,3,8,5,10,6] ------>然后为1列,直接对数组进行“插入排序”即可
public class ShellSort { /** * 我们可以简单的认为shell排序就是“列排序” * @param sources */ public static void sort(int[] sources){ int l = sources.length; int i = l; do{ i = i/2;//列数,“在逻辑上”有多少列数据, insert(sources,i,l); }while(i > 1); } private static void insert(int[] sources,int i,int length){ int j; //i为当前的列数 //lenght:为总数据两 //j为当前排序时,在一列中所处的位置 for(int t = i;t < length; t++){ j = t - i; int cv = sources[t]; while(j >=0 && cv < sources[j]){ sources[j + i] = sources[j]; sources[j] = cv; j = j-i; } } } /** * @param args */ public static void main(String[] args) { int[] sources = {2,15,3,100,87,3,-1,3,0}; sort(sources); System.out.println(Arrays.toString(sources)); } }
相关推荐
`Algorithm.java`文件可能包含了这些排序算法的Java实现代码,而`常见排序算法的实现与性能比较.doc`文档则可能详细比较了这些算法的性能和适用场景。`readme.txt`文件可能是对整个项目的简要说明,包括如何运行和...
这个名为"Java各种排序算法代码.zip"的压缩包包含了一系列实现不同排序算法的Java源代码。排序算法是计算机科学中的基本概念,用于对一组数据进行排列。下面将详细讨论这些算法及其在Java中的实现。 1. 冒泡排序...
本主题将深入探讨Java实现的选择排序算法,这是一种简单直观的排序算法,适合新手学习。 选择排序(Selection Sort)的基本思想是,在未排序的序列中找到最小(或最大)的元素,放到序列的起始位置,然后再从剩余未...
在编程领域,排序算法是数据结构与算法学习中的基础部分,尤其在Java中,了解和掌握各种排序算法对于提升程序性能至关重要。以下是对标题和描述中提到的Java各种排序算法的详细解释,以及它们的实现代码概述。 1)*...
Java排序算法实现 Java排序算法实现 Java排序算法实现
在编程领域,排序算法是计算机科学中的核心概念,特别是在Java这样的高级编程语言中。本文将深入探讨Java中常见的几种排序算法,包括它们的工作原理、优缺点以及如何在实际编程中应用。 首先,我们来看`BubbleSort...
Java 排序算法概述 Java 排序算法是指在 Java 编程语言中使用的各种排序方法,旨在对数据进行有序排列。常见的排序算法有插入排序、交换排序、选择排序、归并排序、分配排序等。 插入排序是最基本的一种排序算法,...
冒泡排序是一种基础且经典的排序算法,主要应用于教学和理解排序的基本原理。...以上就是关于Java实现冒泡排序算法的相关知识点,通过学习和实践,不仅可以掌握冒泡排序,也能为学习更复杂的排序算法打下坚实的基础。
在编程领域,排序算法是计算机科学中的核心概念,尤其是在Java这样的高级编程语言中。Java提供了丰富的内置库函数,如Arrays.sort(),可以方便地对数组进行排序。然而,理解并掌握各种排序算法对于优化程序性能、...
在编程领域,排序算法是计算机科学中的核心概念,特别是在Java这样的高级编程语言中。排序算法是用来组织和优化数据结构的关键工具,它可以帮助我们快速查找、分析和处理数据。本资源包含的是Java实现的各种常见排序...
Java选择排序算法是一种简单直观的排序算法,它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。这种算法对列表中的数据进行了一次完整...
java排序算法java排序算法插入选择冒泡java排序算法插入选择冒泡
本文将深入探讨标题"常用排序算法java演示"中涉及的知识点,包括排序算法的原理、Java实现方式以及其在实际应用中的图形演示。 首先,让我们逐一了解几种常见的排序算法: 1. **冒泡排序(Bubble Sort)**:这是一...
Java 快速排序,目前来说效率很高的一种排序算法,好理解。
5. **归并排序(Merge Sort)**:也是基于分治法的排序算法,将序列分为两半,分别进行排序,然后将两个有序子序列合并成一个完整的有序序列。归并排序在任何情况下都能保证O(n log n)的时间复杂度。 6. **堆排序...
4. **优化与应用**:根据实际场景选择合适的排序算法,并考虑如何优化,比如使用并行或并发策略提高排序速度。 综上所述,掌握这些排序算法和二分查找技巧对于Java程序员来说至关重要,它们不仅能提升编程能力,也...
### Java版本排序算法详解 #### 插入排序 插入排序是一种简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。在Java中,我们可以创建一个`...