本文共 5139 字,大约阅读时间需要 17 分钟。
调整为大根堆:
void shif(int a[],int low,int high){ int i = low,j = 2*i;//j为左孩子 int temp = a[i]; while(j <= high) { if(j < high && a[j] < a[j+1])//如果右孩子更大 j++; if(temp < a[j]){ //如果根节点小于最大孩子 a[i] =a[j];//将a[j]调整到双亲结点位置上 i = j; j = 2*i;//继续向下调整 } else break;//如果根节点大于等于最大的左右孩子 } a[i] = temp;}void HeapSort(int a[],int n){ int i; for(i = n/2;i >= 1;i--) { shif(a,i,n);//初始化循环建立堆 } for(i = n;i >= 2; i--)//进行n-1趟堆排序,每一趟堆中元素个数减一 { swap(a[i],a[1]);//将最后一个元素与a[1]交换 shif(a,1,i-1);//对a[1..i-1]进行筛选,得到i-1个结点的堆 }} int main() { int a[6]={ 0,11,74,3,15,6};HeapSort(a,5);for(int i = 1;i <= 5;i++)cout< <<" "; }
应用:STL中的priority_queue优先队列
一旦元素在优先队列容器中,删除操作将删除最高优先级元素涉及知识点:
priority_queue中元素的比较 模板申明带3个参数:priority_queue<Type, Container, Functional>Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector。
比较方式默认用operator<,所以如果把后面2个参数缺省的话,优先队列就是大顶堆(降序),队头元素最大 仿函数本质就是类重载了一个operator(),创建一个行为类似函数的对象。templatestruct greater : public binary_function { bool operator()(const T& x, const T& y) const { return x > y; }};
题目思路:假设元素类型为int,有序数组的个数为max,利用堆结构,堆中结点类型为node,用vectormyv存储结果。
下面是假如有三个有序数组,找出前三个最小的元素的代码:#include#include #include #define max 3struct node{ //小根堆的结点类型 int pn;//段号 int sn;//该段号中元素的序号 int data;//元素值};struct cmp{ bool operator() (const node& s1, const node& s2)const { return s1.data > s2.data;//创建小根堆 }};void Top(int *a[max],vector &myv){ priority_queue , cmp>qu;//优先队列,注意其中的三个参数 这样每次出队时都是元素值最小的结点 struct node e; for(int i = 0;i < max; i++) { e.pn = i; e.sn = 0; e.data = a[e.pn][e.sn];//将所有段的首元素入队 qu.push(e); } for(int i = 0;i < max; i++) { e = qu.top(); qu.pop();myv.push_back(e.data);//元素值插入到vector中e.sn++;//该段的下一个元素入队e.data = a[e.pn][e.sn];qu.push(e); }}void dis(vector p){ vector ::iterator it; for(it = p.begin() ; it != p.end(); it++) { cout<< *it<<" "; }} int main() { int a1[3] = { 2,6,9};int a2[3] = { -1,-1,5};int a3[3] = { -3,2,4};vector my;int *a[max];a[0] = a1;a[1] = a2;a[2] = a3;Top(a,my);dis(my); }
与上一题类似,利用小根堆,先将a[0]+b[0]插入到小根堆qu中,当k>0时循环,出队元素e,插入到result中,k–,vector<node>result存放结果
void Top(int a[],int b[],int n,int k,vector&p)//求前k个最小和{ priority_queue qu;//优先队列,注意跟上一题比较,这里只需要一个参数 这样每次出队时都是元素值最小的结点 struct node e,temp; e.i = 0; e.j = 0; e.data = a[e.i]+b[e.j]; qu.push(e); while(k) { e = qu.top(); qu.pop();p.push_back(e);k--;if(e.j+1 < n){ temp.i = e.i;temp.j = e.j + 1;temp.data = a[temp.i++]+b[temp.j];qu.push(temp);}if(e.j == 0 && e.i+1< n)//将a[e1.i+1]+b[e1.0]入队{ temp.i = e.i+1;temp.j = e.j;temp.data = a[temp.i]+ b[temp.j];qu.push(temp);} }}void dis(vector p){ for(int i = 0;i < p.size(); i++) { cout<< p[i].data<<" "; }} int main() { int a[3] = { 2,4,5};int b[3] = { 1,2,6};vector vec;Top(a,b,3,6,vec);dis(vec); }
注:在b没有扫描完时将a[e1.i]+b[e1.j+1]入队,当e.j = 0时还要将a[ei.i+1]+b[e1.0]入队
经过自己的试验,去掉e.j == 0 && 这句话,输出结果也是一样的
首先读入k个元素,假设第一次读取的k个元素就是前k个最大元素,把k个元素建成小根堆,然后从第k+1个元素开始,读取的每个元素d都与堆顶元素进行比较,如果元素d大于堆顶元素,则把堆顶的元素替换成d,再将其调整为小根堆,当所有数据都读入并比较完之后,这个小根堆里面的所有元素就是最大的k个元素。
分为自底向上的非递归过程和自顶向下的递归过程,每一趟产生的是局部有序区, 其最好 最坏 平均时间复杂度均为o(nlog2n)
是不稳定的排序算法。 空间复杂度为o(n) (快速排序的空间复杂度是o(log2n)可以采用归并排序,在合并的过程中计算逆序数,这是一种高效的算法,时间复杂度远小于暴力解法。
设low<=i<=mid,mid+1<=j<=high,当a[i]<=a[j]时不产生逆序对,当a[i]>a[j]时逆序数有mid-i+1个(注意两半分别已经排好序了)int sum;void merge(int a[], int low, int mid, int high){ int i = low; int j = mid + 1; int *tmp = (int *) malloc((high - low +1)* sizeof(int));//分配足够空间 int k = 0; while(j <= high && i <= mid) { if(a[i] > a[j]){ sum += mid - i + 1; tmp[k++] = a[j++];}else tmp[k++] = a[i++]; } while(j <= high) tmp[k++] = a[j++]; while(i <= mid) tmp[k++] = a[i++]; for(int k1 = 0;k1 < k;k1++) a[low+k1] = tmp[k1];//把tmp[0..k-1]复制到a[low..high]中 free(tmp);//释放空间}void merge_sort(int a[],int low,int high){ if(low < high){ //注意一开始的条件判断 int mid = (low + high)/2; merge_sort(a,low,mid);//先不断递归 得到最底层的数字 再合并 merge_sort(a, mid+1, high); merge(a,low,mid,high); }} int main() { int a[5] = { 3,1,4,5,2};merge_sort(a, 0, 4);cout<
快速排序之所以比较快,是因为相比冒泡排序,每次交换是跳跃式的。每次排序的时候设置一个基准点,将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数全部放到基准点的右边。这样在每次交换的时候就不会像冒泡排序一样只能在相邻的数之间进行交换,交换的距离就大得多了。因此总的比较和交换次数就少了,速度自然就提高了。当然在最坏的情况下,仍可能是相邻的两个数进行了交换。因此快速排序的最差时间复杂度和冒泡排序是一样的,都是O(N2),它的平均时间复杂度为O (NlogN)。其实快速排序是基于一种叫做“二分”的思想。
#includeint a[101],n;//定义全局变量,这两个变量需要在子函数中使用void quicksort(int left,int right){ int i,j,t,temp;if(left>right)return;temp=a[left]; //temp中存的就是基准数i=left;j=right;while(i!=j){ //顺序很重要,要先从右往左找while(a[j]>=temp && i
转载地址:http://pxten.baihongyu.com/