十大经典排序算法详细总结(含JAVA代码实现)_Java学习之道-CSDN博客
算法的时间与空间复杂度(一看就懂)_不止思考-CSDN博客_空间复杂度
冒泡排序
直接交换
代码
int[] arr={23,12,14,34,1,0,34};
for(int i=0;i<arr.length;i++){
for (int j=0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
for(int i=0;i<arr.length;i++){
System.out.println(arr[i]);
}}
选择排序
先记录再交换
代码
//选择排序
int[] arr = {23, 12, 14, 34, 1, 0, 34};
int min=arr[0];
for(int i=0;i<arr.length;i++) {
int index=i;
for (int j = i + 1; j < arr.length; j++) {
if (arr[j]<arr[index] ) index=j;
}
int temp=arr[i];
arr[i]=arr[index];
arr[index]=temp;
}
for(int i:arr) System.out.println(i);
简单快速排序
对冒泡的一种改进,二分思想
快速排序(java实现)_王玉Student的博客-CSDN博客_java快速排序
ublic static void main(String[] args) {
//快速排序(二分思想)
int[]arr={12,2,34,45,21,3};
quicksort(arr,0,arr.length-1);
for(int i:arr) System.out.println(i);
}
private static void quicksort(int[]arr,int start,int end){
//递归出口否则会栈溢出
if(start>end) return;
//因为start和end不能变 所以用一个变量来存储
int l=start,r=end;
int priov=arr[l];
while(l<r){
/* 假如最好的情况是一个有序序列 1 3 5 7 9,如果先从左边开始寻找的话,一直往右寻找大于1的数,直到i变成4还没有找到就停止了;但是下面的语句就会把9赋值在1上了。
如果先从右边开始寻找的话,一直往左寻找小于1的数,直到j变成0还没有找到然后停止,此时i和j都是0,所以就是把自身交换一下并不影响顺序。
* 这也是为什么强调如果选择数组左边第一个数作为基准值的时候,得先从右边开始查找数。*/
while(arr[r]>=priov && l<r) r--;
while (arr[l]<=priov && l<r) l++;
int temp=arr[l];
arr[l]=arr[r];
arr[r]=temp;
}
//后将基准位与i和j相等位置的数字交换
//下面的i和j其实相等的,所以用哪一个都一样
arr[start]=arr[l];
arr[l]=priov;
quicksort(arr,start,r-1);
quicksort(arr,r+1,end);
}
堆排序
白话讲排序系列(六) 堆排序(绝对让你明白堆排序!)_夜阑听风-CSDN博客_堆排序
【堆本质:1.完全二叉树+2.所有父节点的值都大于(小于)子节点的值】
大顶堆{降序}、小顶堆{升序}
概念:若在输出堆顶的最小值(最大值)后,使得剩余n-1个元素的序列重又建成一个堆,则得到n个元素的次小值((次大值)..…如此反复,便能得到一个有序序列,这个过程称之为堆排序。
在完全二叉树中所有以叶子结点(序号i > n/2)为根的子树是堆。
从最后一个非叶子节点(n/2),依次进行调整(n/2-1、n/2-2...1).
1.父结点索引:(i-1)/2(这里计算机中的除以2,省略掉小数)
2.左孩子索引:2*i+1
3.右孩子索引:2*i+2
对于大顶堆:arr[i] >= arr[2i + 1] && arr[i] >= arr[2i + 2]
对于小顶堆:arr[i] <= arr[2i + 1] && arr[i] <= arr[2i + 2]
堆结构在逻辑上是完全二叉树,物理存储上是数组
public class paixu {
//堆排序
public static void main(String[] args) {
int[] arr=new int[]{2,1,4,3,6,5,8,7};
System.out.println("排序前"+Arrays.toString(arr));
heapsort(arr);
System.out.println("排序前"+Arrays.toString(arr));
}
public static void heapsort(int[] arr){
int len=arr.length;
//构建大顶堆,就是把待排序序列,变成一个大顶堆结构的数组
//从最后一个叶子节点开始从下至上,从右至左,向前遍历,调整节点性质,使之成为大顶堆。
for(int i=len/2-1;i>=0;i--){
//初始化时 从最后一个有子节点往上调整最大堆。
heapify(arr,i,len);
}
//交换栈顶和当前得末尾的节点,重置大顶堆
for(int i=len-1;i>0;i--){
// 元素交换
// 说是交换,其实质就是把大顶堆的根元素,放到数组的最后;换句话说,就是每一次的堆调整之后,都会有一个元素到达自己的最终位置
swap(arr,0,i);
//元素交换之后,毫无疑问,最后一个元素无需再考虑排序问题了。
// 接下来我们需要排序的,就是已经去掉了部分元素的堆了,这也是为什么此方法放在循环里的原因
// 而这里,实质上是自上而下,自左向右进行调整的
//当有一个元素弹出到末尾时,下一次的调整从开头开始【即0】。从顶点开始往下调整,自上而下,自左到右
// 无需考虑最后一个元素 所以放到循环里
heapify(arr,0,i);
}
}
//自上到下,自左到右的一点点调整整棵树,
public static void heapify(int[] arr,int i,int len){
//先根据堆的性质,找出他的左右节点的索引
int left=2*i+1;
int right=2*i+2;
//默认当前节点(父节点)是最大值
int largestIndex=i;
//如果有左节点,并且左节点的值更大,更新最大值的索引
if(left<len && arr[left]>arr[largestIndex]){
largestIndex=left;
}
//如果有右节点,并且右节点的值更大,更新最大值的索引
if(right<len && arr[right]>arr[largestIndex]){
largestIndex=right;
}
if(largestIndex!=i){
//如果最大值不是当前非叶子节点的值,那么就把当前节点和最大值的子节点互换。
swap(arr,largestIndex,i);
//因为互换以后,子节点的值遍历,如果该节点也有自己的子节点,仍需再次调整。
heapify(arr,largestIndex,len);
}
}
public static void swap(int[] arr,int a,int b){
int temp=arr[a];
arr[a]=arr[b];
arr[b]=temp;
}
插入排序
直接插入排序【顺序法定位插入排序】
二分插入排序【二分法定位插入排序】
希尔排序【缩小增量】
public static void main(String[] args) {
int[] arr=new int[]{4,1,34,12,25,8};
insort(arr);
for(int a:arr){
System.out.println(a);
}
}
public static int[] insort(int[]arr){
if(arr.length==0) return arr;
int current,j;
//i表示无序的第一个元素 即要插入的元素 j表示寻找插入位置时的下标
for(int i=1;i<arr.length;i++){
if(arr[i]>arr[i-1]) continue;
//一次查找
//复制插入元素
current=arr[i];
//记录后移,查找插入位置
for(j=i-1;j>=0&¤t<arr[j];j--){
arr[j+1]=arr[j];
}
//将插入元素插入到正确位置
arr[j+1]=current;
}
return arr;
}