排序算法就是那么回事儿<一>
2015-09-12 17:33
246 查看
想来已经大四了,如果真的有什么对大一的自己能说的话,那么就是,其实编程没有什么窍门,无非就是多想,多练。玩玩别被看似复杂的算法给迷住了双眼,其实其核心思想总是只有那么几点。只要多加练习,就能领略其中之美。
另有一点是,有了合适的入门读物,就可以少很多曲折和反复。请注意:合适。这个难度不应该太高,陡峭地让你爬不上去,也不能仅仅是罗列代码。只要能够用自己的语言将这个算法概括出来,那就说明你已经初步掌握了。
算法有多种实现版本,可能你所看到的和书本上的不同,但是这并不妨碍你理解算法的含义
分治法的三个步骤:1.划分问题 2.递归求解 3.合并问题
对归并排序而言
1. 划分问题 :分成长度相等的左右两半
2. 递归求解:把左右两个序列分别进行排序
3. 将结果合为一体 :把两个有序表合为一体
问题的难点在于第三点。
每次将两个有序表中的最小值删除,并且将其放入合并后的新表即可
让我们首先定义一个这个函数的形式
void merge_sort(int* A,int x,int y,int* T);
x,y为操作的范围
注意,这个范围为左闭右开,即[x,y),也就是说实际范围是[x,y-1]
看看核心部分while循环中的部分,有没有一种似曾相识的感觉,从两个序列中得到一个最小的值,这让我们想到了什么?是不是非常像Dijkstra算法(DAG最短路径和算法),Dijkstra算法每次都是从未知的元素中选取d值最小的一点。
另外while循环中有些有技巧的地方,如果q>=y,||运算符就会短路了后面的[]运算(a[y]肯定是非法的)。
归并排序并不美好,它的时间复杂度是O(nlogn),而且需要一个额外的数组T来临时保存结果
和上面一样,我们首先说出其步骤应该是:
划分问题:数组在排序后使得,左侧的值全部都小于右侧值
递归解决:左右分别排序
合并:不需要!
这里插一句题外话,其实快排的发明者就是Tony Hoare,此人1934年出生,到了50岁的时候才对算法发生了兴趣( Tony Hoare’s interest in computing was awakened in the early fifties)。所以告诉我们,算法学得晚其实并不要紧,毕竟,种一棵树最好的时间就是十年前和现在。
另有一点是,有了合适的入门读物,就可以少很多曲折和反复。请注意:合适。这个难度不应该太高,陡峭地让你爬不上去,也不能仅仅是罗列代码。只要能够用自己的语言将这个算法概括出来,那就说明你已经初步掌握了。
算法有多种实现版本,可能你所看到的和书本上的不同,但是这并不妨碍你理解算法的含义
归并排序
归并排序是典型的分治法分治法的三个步骤:1.划分问题 2.递归求解 3.合并问题
对归并排序而言
1. 划分问题 :分成长度相等的左右两半
2. 递归求解:把左右两个序列分别进行排序
3. 将结果合为一体 :把两个有序表合为一体
问题的难点在于第三点。
每次将两个有序表中的最小值删除,并且将其放入合并后的新表即可
让我们首先定义一个这个函数的形式
void merge_sort(int* A,int x,int y,int* T);
x,y为操作的范围
注意,这个范围为左闭右开,即[x,y),也就是说实际范围是[x,y-1]
void merge_sort(int* A,int x,int y,int* T){ if(y-x<=1)return; int m=(x+y)/2; merge_sort(A,x,m,T); merge_sort(A,m,y,T); int p=x,q=m,i=x;//分别是左序列、有序列、新序列的下标 while(p<m||q<y){ if(q>=y||A[p]<=A[q]) T[i++]=A[p++]; else T[i++]=A[q++] } for(int i=x;i<y;i++)//从辅助数组中转移回来 A[i]=T[i]; }
看看核心部分while循环中的部分,有没有一种似曾相识的感觉,从两个序列中得到一个最小的值,这让我们想到了什么?是不是非常像Dijkstra算法(DAG最短路径和算法),Dijkstra算法每次都是从未知的元素中选取d值最小的一点。
另外while循环中有些有技巧的地方,如果q>=y,||运算符就会短路了后面的[]运算(a[y]肯定是非法的)。
归并排序并不美好,它的时间复杂度是O(nlogn),而且需要一个额外的数组T来临时保存结果
快速排序
快速排序的最差时间为O(n^2),平均情况O(nlogn)和上面一样,我们首先说出其步骤应该是:
划分问题:数组在排序后使得,左侧的值全部都小于右侧值
递归解决:左右分别排序
合并:不需要!
//网上的快速排序很多,这里举一例Hoare版本,这个版本比较好理解 int partition(int* a,int l,int r){ int key=a[0]; int left=l,right=r; while(left<right){ while(key<=a[right]&&right>left)right--; a[left]=a[right]; while(key>=a[left]&&right>left) left++; a[right]=a[left]; } a[left]=key; return left; }
void quick_sort(int* a,int left,int right){ int p=partition(a,left,right); quick_sort(a,left,p-1); quick_sort(a,p+1,right); }
这里插一句题外话,其实快排的发明者就是Tony Hoare,此人1934年出生,到了50岁的时候才对算法发生了兴趣( Tony Hoare’s interest in computing was awakened in the early fifties)。所以告诉我们,算法学得晚其实并不要紧,毕竟,种一棵树最好的时间就是十年前和现在。
相关文章推荐
- CSS布局中左(右)宽度自适应,右(左)宽度固定
- 使用Double类创建double类型变量
- C# Webkit GetElementById Click
- C++指针和引用简介
- 排序算法就是那么回事儿<一>
- <Chapter 2>2-2-2.开发Java应用(Developing a Java App)
- c++11——lambda表达式
- yum安装与管理
- week1-7Observations
- bootstrap第三天
- jquery treeview(树状菜单) 插件参数说明
- php 中json_decode函数的用法
- Java JNI实现原理初探
- NSMapTable、NSHashTable与NSPointerArray的封装
- 数据库相关总结
- 【LeetCode】223. Rectangle Area
- 烂泥:vcenter5.5无AD下的安装与配置
- 缘起“图像检索”
- 5.5 USB虚拟化
- jsessionId的使用