您的位置:首页 > 移动开发 > IOS开发

漫步IOS--部分排序一:冒泡排序、选择排序和快速排序

2014-12-26 14:39 309 查看
1 冒泡排序

冒泡排序的思路:从序列的一头开始,每次比较相邻的两个数,将大的往后移.当走到序列结尾的时候,最后一个即是最大的;然后再从头开始比较,只是这次比较到倒数第二个就好,因为最后一个已经确定是最大了。如此往复,直到没有需要比较的元素为止。个人表述有限,可参考维基百科介绍。
参考代码:
//冒泡排序
void sortUp(int arr[],int size){
for (int i = 0; i < size ; i++) {
for (int j = size-1; j > i; j--) {
if(arr[i] > arr[j]){
arr[i] += arr[j];
arr[j] = arr[i] - arr[j];
arr[i] = arr[i] - arr[j];
}
}
}
}


时间复杂度:
冒泡排序一般是作为程序员入门算法进行讨论的,因为他的效率着实有些低。别的不说,相比选择排序就落好几条街。
最好时间复杂度是O(n);
这种情况是: 6 , 1, 2, 3, 4, 5, 类似吧。即只需一趟即可把顺序完全排好。出现的概率有点儿低。
最坏时间复杂度是O(n2);
这种情况是:6,5,4,3,2,1类似吧,即每一趟的每一次比较都需要进行数据交换。对此不予评论。
2 选择排序
选择排序的思路:每一趟扫描选取剩下的元素中一个最大的放在后边。他与冒泡排序的区别在于,在扫描的过程中,只是保留选中元素的下标,而并不是将元素进行位移。更换选中的数据也只是更换一下下标的值,中间不会产生数据移动。所以在效率上会高很多很多。
参考代码
//选择排序
void sortSelect(int arr[],int size){
int re[size];
for (int i = 0; i < size; i++) {
int min = i;
for (int j = i+1; j < size; j++) {
if (arr[min] > arr[j]) {
min = j;
}
}
if(min != i){
arr[i] += arr[j];
arr[j] = arr[i] - arr[j];
arr[i] = arr[i] - arr[j];
}
}
}


时间复杂度:

比较次数O(n2),交换次数O(n),因为在计算机中交换的CPU时间需要的比比较所需要的CPU时间要长的多,所以选择排序比冒泡排序要快许多。最好情况是,已经有序,交换0次;最坏情况是,逆序,交换n-1次。

3 快速排序
快速排序的思路:在序列中选择一个标杆,通常选择序列的第一个数,然后对序列中的数从两头开始,将小于他的数放在左边,大于他的数放在他右边。这时以这个数为标杆,分成了左右两块,左边的都小于他,右边的都大于他。然后再递归调用,直到没有可排序的。即只有两个元素。感觉不大容易看懂,所以贴了一个动图来看看。



算法思路:我贴一下百度的讲解吧。

假设用户输入了如下数组:
下标
0
1
2
3
4
5
数据
6
2
7
3
8
9
创建变量i=0(指向第一个数据), j=5(指向最后一个数据), k=6(赋值为第一个数据的值)。

我们取走了下标0的数据,于是,我们需要找到一个数字来替换他。由于我们要把所有比6小的数移动到左面,所以我们可以开始寻找比6小的数并从右往左找。别急,我们要按顺序找哦。不断递减j的值,我们发现下标3的数据比6小,于是把3移到下标0(实际是i指向的位置。代码中要用i,因为后面还会循环这个步骤,不用i的话第二次循环:
下标
0
1
2
35
5
数据
3
2
7
3
8
9
i=0 j=3 k=6

由于变量k已经储存了下标0的数据,所以我们可以放心的把下标0覆盖了。如此一来,下标3虽然有数据,但是相当于没有了,因为数据已经复制到别的地方了。于是我们再找一个数据来替换他。这次要变成找比k大的了,而且要从前往后找了。递加变量i,发现下标2是第一个比k大的,于是用下标2的数据7替换j指向的下标3的数据,数据状态变成下表:
下标
0
1
2
3
4
5
数据
3
2
7
7
8
9
i=2 j=3 k=6

重复上面的步骤,递减变量j。这时,我们发现i和j“碰头”了:他们都指向了下标2。于是,循环结束,把k填回下标2里,即得到结果。

填回k之后状态为:
下标
0
1
2
3
4
5
数据
3
2
6
7
8
9
如果i和j没有碰头的话,就递加i找大的,还没有,就再递减j找小的,如此反复,不断循环。注意判断和寻找是同时进行的。

注意:快速排序不会直接得到最终结果,只会把比k大和比k小的数分到k的两边。(你可以想象一下i和j是两个机器人,数据就是大小不一的石头,先取走i前面的石头留出回旋的空间,然后他们轮流分别挑选比k大和比k小的石头扔给对面,最后在他们中间把取走的那块石头放回去,于是比这块石头大的全扔给了j那一边,小的全扔给了i那一边。只是这次运气好,扔完一次刚好排整齐。)为了得到最后结果,需要再次对下标2两边的数组分别执行此步骤,然后再分解数组,直到数组不能再分解为止(只有一个数据),才能得到正确结果。

参考代码:

//快速排序
void sortQuickly(int arr[],int low,int high){
//m代表前面的标记,n代表后面的标记。L表示当前的中间位
int m = low,n = high;
int temp = arr[low];
if (low < high) {
while(m < n){
while((arr
>= temp) &&  (m < n)){
n--;
}
arr[m] = arr
;
while((arr[m] <= temp) &&  (m < n)){
m++;
}
arr
= arr[m];
}
arr
= temp;
sortQuickly(arr,low,m-1);
sortQuickly(arr,n+1,high);
}else{
return;
}
}


时间复杂度:

快速排序是面试题中经常会提到的排序算法之一。也是最容易让人产生忘性的,建议多敲几遍加强一下记忆。

最差时间复杂度:O(n2)

最好时间复杂度:O(nlogn)

今天写的匆忙,后面会再修改更新。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐