关于排序的一些算法(自己复习用的)

1、快速排序精髓

一、先从数列中取出一个数作为基准数

 二、分区,将比这个数大的数全放到它的右边,小于或等于它的数全部放到它的右边

 三、对左右区间重复步骤(二),直到各区间只有一个数为止

#include<bits/stdc++.h>
using namespace std;
void qsort(int a[],int l,int r){
    if(l>=r) return ; ///找完了
     int x=a[l+r>>1];///选中间数为基数然后去快排
     int i=l-1,j=r+1;///先越界范围处理 因为下面是先--和++
     while(i<j){
        while(a[++i]<x);//找到第一个比它小的
        while(a[--j]>x);///找到第一个比它大的
        if(i<j) swap(a[i],a[j]); ///交换
     }
     qsort(a,l,i);///将找到的大于和小于基数的两边分    
     qsort(a,i+1,r);
}
int main(){
   int a[100];
   int n; cin>>n;
   for(int i=1;i<=n;i++) cin>>a[i];
   qsort(a,1,n);
   for(int i=1;i<=n;i++) cout<<a[i]<<" ";
   return 0;
}

2.归并排序(Merge Sort)(知乎上大佬看到的传送门附上,方便回顾点这里
该算法是利用分治思想解决问题的一个非常典型的应用,归并排序的基本思路就是先把数组一分为二,然后分别把左右数组排好序,再将排好序的左右两个数组合并成一个新的数组,最后整个数组就是有序的了。

运用递归法实现归并操作的主要步骤:
1.申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列。
2.设定两个指针,最初位置分别为两个已经排序序列的起始位置。
3.比较两个指针所指向的元素,选择较小的元素放入到合并空间,并将指针移动到下一位置。
4.重复步骤3直到某一指针到达序列尾,然后将另一序列剩下的所有元素直接复制到合并序列尾
在这里插入图片描述


#include<iostream>
#include<vector>

using namespace std;

void Merge(vector<int>& , int , int , int );
void MergeSort(vector<int>& , int , int );

int main() {
    vector<int> test = { 3, 7, 6, 4, 5, 1, 2, 8 };
    MergeSort(test,0,test.size()-1);

    for (auto x : test)
        cout << x << " ";

    return 0;
}


void Merge(vector<int>& arr, int left, int mid, int right) {
    int i = left;
    int j = mid + 1;
    int k = 0;
    vector<int> temp(right - left + 1);
    while (i <= mid && j <= right)
        temp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++];

    while (i <= mid)
        temp[k++] = arr[i++];

    while (j <= right)
        temp[k++] = arr[j++];

    for (int m = 0; m < temp.size(); m++)
        arr[left + m] = temp[m];
}


void MergeSort(vector<int>& arr,int left, int right) {
    if (left >= right) return;

    int mid = left + (right - left) / 2;
    MergeSort(arr, left, mid);
    MergeSort(arr, mid + 1, right);
    Merge(arr, left, mid, right);
}

今天是2021/7/3,又去学到一个排序 ,堆排大佬博客传送门点开他啊


堆排序

什么是堆?堆的用处?


堆:完全二叉树 + 满足某种条件(父亲结点比左右儿子小 或 父亲结点比左右儿子大)
堆(heap)有时被称为优先队列(priority queue)。堆和队列有相似地方,在堆底插入元素,在堆顶取出元素,但是堆中元素的排列不是按照到来的先后顺序,而是按照一定的优先顺序排列的

算法分析

以小根堆为例
小根堆:父亲结点比左右儿子小
堆最好能满足一下五个功能

  1. 插入一个数
  2. 求集合中的最小值
  3. 删除最小值
  4. 删除集合中任意一个数
  5. 修改集合中任意一个数
    STL中的priority_queue可以实现功能1,2,3
    而我们如何自己手写一个堆可以实现功能1,2,3,4,5

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

down()和up()函数代码模版

// 值变化,往下维护
void down(int u) {
    int t = u; // t记录最小值的下标
    if (2 * u <= size_ && h[2 * u] < h[t]) t = 2 * u; // 左儿子存在,且值比父亲小
    if (2 * u + 1 <= size_ && h[2 * u + 1] < h[t]) t = 2 * u + 1; // // 右儿子存在,且值比父亲小
    if (t != u) {
        swap(h[t], h[u]);
        down(t);
    }
    return;
}

// 值变化,往上维护
void up(int u) {
    if (u / 2 > 0 && h[u / 2] > h[u]) {
        swap(h[u / 2], h[u]);
        up(u / 2);
    }
    return;
}

C++代码模板

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define fio ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define mse(a,b) memset(a,b,sizeof a)
#define pb push_back
#define pii pair<int,int>
using namespace std;
const int mod = 1e9 + 7;
const int maxx = 1e6 + 10;
const double eps = 1e-6;
using namespace std;
const ll inf = 0x3f3f3f3f3f3f3f;
const long double PI = 3.14159265358979323846;
//inline ll read(){ ll x=0,f=1; char ch=getchar(); while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); } while (isdigit(ch)) { x=x*10+ch-48;  ch=getchar();  } return x*f;}
// ll cc = ((1ll << 62) - 1 + (1ll << 62));
/*struct node {
	ll l,r ,lazy,val;
	node() :l(),r(),lazy(),val(){}
	node(ll a, ll b, ll c,ll d) :l(a),r(b),lazy(c),val(d){}

};*/
int a[maxx],n;
void down(int x){
    int t=x;
    if(x*2<=n&&a[x*2]<a[t]) t=x*2;
    if(x*2+1<=n&&a[1+x*2]<a[t]) t=x*2+1;
    if(t!=x){
        swap(a[t],a[x]);
        down(t);
    }
}

void up(int u) {
    if (u / 2 > 0 && a[u / 2] > a[u]) {
        swap(a[u / 2], a[u]);
        up(u / 2);
    }
    return;
}
int main(){
    fio n=100;
    for(int i=1;i<=n;i++) a[i]=rand()%1007;
    for(int i=n/2;i>=1;i--) down(i);

    while(n){
      cout<<a[1]<<" ";
      a[1]=a[n];
      n--;
      down(1);
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值