算法 简单来说就是用有限步骤解决问题的方法,而描述解决问题的步骤,可以用各类计算机语言,java,c,python等,甚至用流程图或者数学符号等抽象的语言,只要可以在有限个步骤能完成即可
排序算法不会以问题直接出现,而是会在算法题目中用到,甚至不会连算法都不会出现,只是出现排序算法的思想,比如求某n长数列第k大的数,虽然直观感觉很简单,但是如果只是对数列进行冒泡排序,再取第k大的数,其时间复杂度可能会无法接受,就这个问题来说,刚才提到的算法是不好的,因为其实我们只是求第k大,k以后的排序其实是浪费的
算法问题更多的会以上面的形式出现,所以需要我们学会几个排序算法的思想,然后根据不同的问题去选择,下面提到的排序规则都是按照从小到大,这对算法本身正误是没有影响的,这样做只是为了说明方便节省时间
回忆下冒泡排序,直接给出数列
一 23 23 23 23
90 9 9 9
9 90 25 25
25 25 90 16
16 16 16 90 通过第一轮冒泡 最大的元素90到达了末尾
二 9 9 9
23 23 23
25 25 16
16 16 25 通过第二轮冒泡 25到达了末尾
90 90 90
三 9 9
23 16
16 23 通过第三轮冒泡 23到达了末尾
25 25
90 90
四 9 完成排序
16
23
25
90
对于n长的数组我们需要(n*n-1)/2次比较 时间复杂度为O(n^2)
再给出快速排序示例
⇩
6 1 2 7 9 3 4 5 10 8
⇩
6 1 2 7 9 3 4 5 10 8
⇩
6 1 2 7 9 3 4 5 10 8
⇩
6 1 2 7 9 3 4 5 10 8
⇩
5 1 2 7 9 3 4 6 10 8
⇩
5 1 2 7 9 3 4 6 10 8
⇩
5 1 2 7 9 3 4 6 10 8
⇩
5 1 2 6 9 3 4 7 10 8
⇩
5 1 2 4 9 3 6 7 10 8
⇩
5 1 2 4 6 3 9 7 10 8
5 1 2 4 3 6 9 7 10 8 比较了10次 而6左边的数都小于6 6右边的数都大于6
然后数组分成了两部分 6左边 6右边即
5 1 2 4 3和 9 7 10 8
我们对这两个数组分别进行快速排序,这里就是用的递归的思想,只给出左边的后续步骤
⇩
5 1 2 4 3
⇩
5 1 2 4 3
⇩
3 1 2 4 5
⇩
3 1 2 4 5
⇩
3 1 2 4 5
⇩
3 1 2 4 5
3 1 2 4 5
新数组变成5左边 3124 右边没有
⇩
3 1 2 4
⇩
3 1 2 4
⇩
3 1 2 4
⇩
2 1 3 4
2 1 3 4
新数组变成 3左边 21 右边4
⇩
4
⇩
2 1
⇩
1 2
新数组变成2左边1 右边没有
⇩
1
回到第一次的递归
就是123456 9 7 10 8
9 7 10 8留做作业,做为思考
直观感觉每进行一次快速排序,数组都被分为两部分,而下一次排序只会遍历被拆分的部分,所以直观来看,确实比冒泡排序要更加有效,考虑一般情况,每次等分两部分,则时间复杂度为o(n log(n))而最极端的情况 即完全倒序,快速排序退化为冒泡排序 时间复杂度为o(n^2)
给出java的快速排序的实现,给出关键代码
class Solution{
static void quicksort(int[] arr,int i,int j) {
int a=i;
int b=j;
if(a==b) {
return;
}
int temp=arr[a];
while(a!=b) {
while(temp<arr[b]&&a<b) {
b--;
}
if(a==b) {
break;
}
arr[a]=arr[b];
a++;
while(arr[a]<temp&&a<b) {
a++;
}
if(a==b) {
break;
}
arr[b]=arr[a];
}
arr[a]=temp;
if(a>i) {
quicksort(arr,i,a-1);
}
if(a<j) {
quicksort(arr,a+1,j);
}
}
}
编写主函数使用测试数据数组测试上述代码,留做作业
刚才提到的求n长数组第k大元素,可以用快速排序的思想,进行一次快速排序,判断如果k>a,对(i,a-1)进行递归,如果k<a,对(a+1)进行递归,具体实现留做作业