算法学习小心得——基于比较的排序算法汇总
2013-10-22 22:33
465 查看
这几天学习了基于比较的排序算法,有插入排序、归并排序、堆排序和快速排序。下面自己用C++代码实现了一下:
1、插入排序,插入排序的思想比较简单,就是像我们打扑克牌把手中的牌整理好一样,假设手中的牌是已经排好的,只需要找找到适当的位置把下一张牌插入到已有的牌中就好了。
2、归并排序,归并排序使用了分治的方法,即把问题分为若干个子问题再分别解决每个子问题。主要思想是这样的,如果a和b是两个已经排好序的数组,那么可以比较a和b中的元素大小,把他们合并成一个排好序的数组。所以就把整个要排序的数组进行划分,直到每个字数组中只有一个元素(一个元素肯定是排好序的)。然后开始合并,直到最后合并成原长度的数组。这里用了一个Merge作为合并函数。
3、堆排序,堆排序是使用了最大堆这种数据结构。最大堆就是堆顶的元素是堆中最大的。堆排序的主要思想就是用数组来构造最大堆。这样每次把堆顶元素和数组中最后一个元素调换位置,直到堆中只有一个元素,这样数组的元素就从大到小了。这个算法写了一个堆的类,用成员函数进行排序。
4、快速排序,这个排序相对比较难懂,也是用了分治的策略。把目标数组的最后一个元素作为主元素,然后对前n-1个进行遍历,试数组被分为起点到i,i到j,j到末尾3段,第一段的数都小于主元素,第二段的数都大于主元素,第三段没有排,然后知道第三段的元素都被移除到第一段和第二段。再把主元素和到i+1的位置(大于主元素的位置)的元素调换,这样就被分成了两段,前一段都小于主元素,后一段都大于主元素。再对这两段递归的执行相同算法。
除了插入排序的时间复杂度是N平方外,其他都是nlgn,对于快速排序来说这个时间复杂度是平均的,而不是最坏的,当然如果随机的来选取主元素的话,是可以打到更好的效果,这里需要的数学证明比较多,就不说了哈。nlgn也是基于比较排序的算法的时间复杂度下限,也就是最优的。其中归并排序不是原址的,也就是会占用和问题大小相关的存储空间。其他三个算法都是原址的。
1、插入排序,插入排序的思想比较简单,就是像我们打扑克牌把手中的牌整理好一样,假设手中的牌是已经排好的,只需要找找到适当的位置把下一张牌插入到已有的牌中就好了。
void InsertionSort(int *A,int beg,int end){ int key; for(int i=beg+1;i<=end;i++){//对所有的牌进行遍历,假设手中只有一张牌。 key=A[i];//用key来表示要插入的牌 int j=i-1; while(j>=0 && A[j]>key){//找到正确的位置:如果手中的牌比要插入的大就往后移,直到正确的位置 A[j+1]=A[j]; j--; } A[j+1]=key;//把要插入的牌放到正确的位置 } }
2、归并排序,归并排序使用了分治的方法,即把问题分为若干个子问题再分别解决每个子问题。主要思想是这样的,如果a和b是两个已经排好序的数组,那么可以比较a和b中的元素大小,把他们合并成一个排好序的数组。所以就把整个要排序的数组进行划分,直到每个字数组中只有一个元素(一个元素肯定是排好序的)。然后开始合并,直到最后合并成原长度的数组。这里用了一个Merge作为合并函数。
void Merge(int *A,int beg,int mid,int end){//合并函数 int n1=mid-beg+1,n2=end-mid; int i1=beg,i2=mid+1; vector<int> v;//用了一个vector来做中间数组,这里我纯粹是为了练习,完全可以用一个数组 while(i1<=mid && i2<=end){ if(A[i1]<A[i2]){ v.push_back(A[i1++]); } else v.push_back(A[i2++]); } while(i1<=mid){ v.push_back(A[i1++]); } while(i2<=end){ v.push_back(A[i2++]); } int n=beg; auto it=v.begin(); while(it!=v.end()){//将合并好的数组拷入到原数组中 A[n++]=*it; it++; } }
void MergeSort(int *A,int beg,int end){//进行归并 if(beg<end){//如果数组元素不为1,就进行划分 int mid=beg+(end-beg)/2; MergeSort(A,beg,mid); MergeSort(A,mid+1,end); Merge(A,beg,mid,end); } }
3、堆排序,堆排序是使用了最大堆这种数据结构。最大堆就是堆顶的元素是堆中最大的。堆排序的主要思想就是用数组来构造最大堆。这样每次把堆顶元素和数组中最后一个元素调换位置,直到堆中只有一个元素,这样数组的元素就从大到小了。这个算法写了一个堆的类,用成员函数进行排序。
class Maxheap{ private: int size;//存放堆得大小 int length;//存放数组的长度 vector<int> data;//存放堆中元素 public: Maxheap(){size=0;length=0;} void Add(int value){ data.push_back(value); size++; length++; } void MaxHeapify(int i); void BuildMaxheap(); void HeapSort(); int Get(int i){if(i<length)return data[i];else cout<<"overflow";} int Getlen(){return length;} }; void Maxheap::MaxHeapify(int i){//这个函数用来不断的维护堆的性质,因为建堆的时候需要用到,而且调换了堆顶元素和堆中最后一个元素后会破坏堆的性质。 int l=2*i+1,r=2*i+2;//找到左孩子和又孩子的序号 int largest=i,temp; if(l<size && data[l]>data[i]){ largest=l; } if(r<size && data[r]>data[largest]){ largest=r; }//将根、左孩子、右孩子中最大的作为根 if(largest!=i){//如果左子树和右子树的根变化,可能破坏了子树的性质,所以再次对子树进行维护。 temp=data[largest]; data[largest]=data[i]; data[i]=temp; MaxHeapify(largest); } } void Maxheap::BuildMaxheap(){//建堆 size=length; for(int i=length/2-1;i>=0;i--){//因为对树来说,后n/2节点为叶节点,所以不需要维护,只维护前n/2 MaxHeapify(i); } } void Maxheap::HeapSort(){//排序 BuildMaxheap();//先建堆 int temp; while(size>1){//然后不断的把堆顶元素移到堆尾,并且维护堆的性质 temp=data[size-1]; data[size-1]=data[0]; data[0]=temp; size--; MaxHeapify(0); } }
4、快速排序,这个排序相对比较难懂,也是用了分治的策略。把目标数组的最后一个元素作为主元素,然后对前n-1个进行遍历,试数组被分为起点到i,i到j,j到末尾3段,第一段的数都小于主元素,第二段的数都大于主元素,第三段没有排,然后知道第三段的元素都被移除到第一段和第二段。再把主元素和到i+1的位置(大于主元素的位置)的元素调换,这样就被分成了两段,前一段都小于主元素,后一段都大于主元素。再对这两段递归的执行相同算法。
int Partition(int *A,int beg,int end){//用于划分 int key=A[end]; int i=beg-1,j=beg; int temp; while(j<end){ if(A[j]<key){ temp=A[++i]; A[i]=A[j]; A[j++]=temp; } else j++; } temp=A[++i]; A[i]=A[end]; A[end]=temp; return i;//返回后i之前的元素都小于A[i],i之后的都大于A[i] } void QuickSort(int *A,int beg,int end){ if(beg<end){ int p=Partition(A,beg,end); QuickSort(A,beg,p-1); QuickSort(A,p+1,end); } }
除了插入排序的时间复杂度是N平方外,其他都是nlgn,对于快速排序来说这个时间复杂度是平均的,而不是最坏的,当然如果随机的来选取主元素的话,是可以打到更好的效果,这里需要的数学证明比较多,就不说了哈。nlgn也是基于比较排序的算法的时间复杂度下限,也就是最优的。其中归并排序不是原址的,也就是会占用和问题大小相关的存储空间。其他三个算法都是原址的。
相关文章推荐
- 算法:基于比较的排序算法
- 深度学习:基于梯度下降不同优化算法的比较总结
- [算法学习笔记]几个排序算法的比较
- 【Python学习心得】Python数据分析几个比较常用的方法
- 有毒的蘑菇-基于规则学习(独立而治之算法)
- 采用深度学习算法为Spotify做基于内容的音乐推荐
- 基于java的InputStream.read(byte[] b,int off,int len)算法学习
- 算法学习第一章-----排序算法
- StreamDM:基于Spark Streaming、支持在线学习的流式分析算法引擎
- 算法学习之排序算法(五)(高速排序)
- 算法设计和数据结构学习_2(常见排序算法思想)
- 【啊哈!算法】之一、排序算法比较
- 推荐算法:基于svd的算法:比较
- 采用深度学习算法为Spotify做基于内容的音乐推荐
- 多种特征提取算法比较汇总
- 嵌入式每日学习心得 基于TCP/IP的聊天室程序
- StreamDM:基于Spark Streaming、支持在线学习的流式分析算法引擎
- Python 基于语句检测和语句频谱分析实现文本汇总算法 (document summary algorithm)
- 算法学习(1):排序算法-插入排序及python实现
- 学习心得(泛型、算法及其他)