八大排序
1.交换排序:
a.冒泡排序(相邻交换,最大在后)
外循环表示交换多少轮,内循环表示一轮交换多少次,两次循环
时间复杂度为O(n^2)
规律:
(1)外循环一共进行数组大小-1次循环(每循环一次排序一次)
(2)内循环每一次排序次数都在逐渐减小,(因为最大值已经在最后)
优化:如果发现某次排序一次交换都没有,那这个就是排序好的
// 优化
public static void sortwin(int a[]){
int zhuan=0;
// 标记后面一轮是否有过交换
boolean T=false;
// 所有论
for (int j = 0; j a[i+1]){
T=true;
zhuan=a[i];
a[i]=a[i+1];
a[i+1]=zhuan;
}
}
if (!T){
// 如果没有交换那证明已经排序完成
break;
}else{
// 重置
T=false;
}
}
// System.out.println(Arrays.toString(a));
}
b.快速排序(重点)
基础思想:
1.首先,会有一个基准值和一个左指针以及右指针(并且要有两个变量保存指针)
2.指针跟基准值比较,小的放在基准值左边,大的放右边(指针移动)
3.这样就会分成左边一个值小的分区和右边值大的分区
4.使用递归重复1,2的操作,直到每一个小分区只有1个数据
public static void quicksot(int nums[],int left,int right){
// 递归退出条件
if (left>right){
return;
}
// 因为后面交换中会更改两个指针,所以先保存
int l=left;
int r=right;
// 定义基准值
int pivot=nums[left];
while (l!=r){
// 45 ,30 , 61 , 82 , 74 , 12 , 26 , 49
// 45 ,30 , 26 , 82 , 74 , 12 , 61 , 49
// 45 ,30 , 26 , 12 , 74 , 82 , 61 , 49
// 12 ,30 , 26 , 45 , 74 , 82 , 61 , 49
// --------------------
// 12 ,30 , 26 , 45 , 74 , 82 , 61 , 49
// 从右边找到小于基准的值
while (nums[r]>=pivot && l
2.插入排序
a.直接插入排序
内循环是移动左分区,外循环移动右分区,两次循环,时间复杂度为O(n^2)
规律:1.将整个数组分为两个分区,left有序区,和right无序区
2.左分区的数跟右分区一个一个比较,小于左分区,就左分区比较的那个值向后挪动
3.循环结束证明右分区的值大于左分区,此时leftindex+1才是插入的下标位置
注:下图中right保存了值,因为下面向后挪动会把值给挤掉
优化:当要插入的位置就是当前位置就不要插入
public void insert(int nums[]){
for (int j = 1; j =0 && nums[leftindex]>right){
// 向后挪动,为插入让出位置,之前理解有误,这里只是值往后挪,不是下标挪
nums[leftindex+1]=nums[leftindex];
// 有序列表向左移动,继续比较
leftindex--;
}
// 1,-1,2,4
// leftindex是要跟右分区比较值的下标,,但是由于要往左边移动,此时+1才是插入的下标
// 优化,如果=j证明插入的位置就是当前位置
if (leftindex+1!=j){
nums[leftindex+1]=right;
}
}
// System.out.println(Arrays.toString(nums));
}
b.希尔排序
希尔排序其实也是一种插入排序,是在插入排序的基础上优化的一种排序算法
有两种能够实现方式能够实现希尔排序:
原理:a.不断分组分到最后一组再进行其他排序
b.分组不断/2,直到为1
(1)交换实现希尔
(2)插入移动实现:在插入外面套一个循环分组
public void winxier(int num[]){
// 跟插入排序区别不大,外面加了个循环分组
// 分组
for (int fenzhu = num.length/2; fenzhu >0 ;fenzhu/=2) {
// 中层循环表示分成几个小组,且j=i指每个小组的后一个
for (int zhu = fenzhu; zhu=0 防止数组越界 num[leftindex]>right只有右边分区小于左边才会进去
while (leftindex>=0 && num[leftindex]>right){
// 左边分区值向后挪动
num[leftindex+fenzhu]=num[leftindex];
// 当前下标值比较完后,下标向左移动,又因为不属为i
leftindex-=fenzhu;
}
// 优化:当判断满足时证明leftindex移动了
if (leftindex-fenzhu!=zhu){
num[leftindex+fenzhu]=right;
}
}
}
// System.out.println(Arrays.toString(num));
}
3.归并排序
使用归并思想实现的排序方法,采用分治的策略,将问题分成多个小问题进行递归求解---分而治之
基本思路:合并次数等于数组长度-1
1.整体分为分 - 治
2.分,怎么分?通过递归向下分,到只有两个数比较为止
3.治,如何治?递归回溯向上合并,在分到最底部开始,
a.比较两个数大小,并使用一个临时数组temp临时储存
b.如果两个序列(最少有1个值)比较完,一方序列还有值,就将剩余的全部放到临时数组temp
c.将临时数组的值再copy到原数组
假如有此数组int nums[]={8,4,5,7,1,3,6,2};
会实现合并7次
//拆分在合并
public static void diguisort(int left,int right,int nums[],int temp[]){
if (left
4.基数排序
基础思路:(用空间换时间)
1.首先有10个桶,因为用的是十进制数
2.每一趟呢就按位数存在桶里,取回原数组
3.会有多少趟?看最大数的位数,假如最大数为345此时最大位数n=3,有3趟
5.选择排序
a.简单选择排序
跟冒泡有丢相似的地方,冒泡大的往后冒,选择是小的往前选
外循环表示交换多少轮,内循环表示找到最小值,两次循环
时间复杂度为O(n^2)
规律:
(1)有数组大小-1轮排序
(2)每一轮排序又会通过循环找到一个最小值
(3)如第一轮找到最小值(1--length)与第一个值a[0]交换,第二轮排序就从
(2--length)里找最小值,找到后与a[1]交换
(4)初始化时定义一个最小值和最小值下标
优化:定义的下标值改变后才交换,没有改变就是当前就是最小值
注:如下图A步骤那里刚开始时一直想着感觉就是保存了最小值,可以拿到下面B步骤那里一起交换,后来发现一直不行,debug半天才发现,里面那个循环,如果不重置最小值的话就会找到最后一个比min小的值而不是最小值,因为最小值min一直没有重置
public static void jishu(int nums[]){
// 求最大数
int max=nums[0];
for (int i = 1; i < nums.length ; i++) {
if (max
b.堆排序