首页 > 编程语言 >C++ 由快排学习到的的随机数等知识

C++ 由快排学习到的的随机数等知识

时间:2022-09-07 18:23:41浏览次数:119  
标签:return nums int C++ 快排 32753 swap 随机数

  • 起:

力扣的912题 数组排序 ,想着先用快速排序来写写,在实际用c++编写的时候,有一些之前没注意到的细节问题造成了一些麻烦。

912. 排序数组 - 力扣(LeetCode)

 

 

 

  • 快排思想

  每次以数组最后一个数为基准,按照波兰国旗问题对数组进行分层(partition)。假设最后一个数为P,则将数组分为小于P、等于P、大于P的3层。之后对小于P和大于P的层进行此过程的迭代。迭代完成后,目标数组即排列完成。

  1.   问题:最坏的结果的O(n^2),因为每次最后一个数当成分层基准,最坏的情况是左右两层极度不平衡
  2.   改进:引入随机数,每次进行分层之前,随机将数组前面的一个数与最后一个数P进行swap,这样分层就成了一个随机事件。在数学证明中,可证明时间复杂度收敛于0(N*LogN)。
  • C++中的随机数

  在c++中,获取随机数一般广为人知的方法是 rand() ,但是这种方法获得的随机数是伪随机数,其原理是从一个已经确定了的序列中按顺序返回整数。

  在直接使用 rand()时,默认的 srand(1)。srand可以认为是种子。

    只使用rand()时

int main() {
    for (int i = 0; i < 10; i++) {
        cout << rand() << "\t";
    }
    return 0;
}

  输出结果(因电脑而异):

    41      18467   6334    26500   19169   15724   11478   29358   26962   24464

  你每次运行,答案和该结果都一致,这是因为种子没变,永远输出的是该序列前十个数字。

  所以有一个思路就是改变种子,想让每次运行的种子发生变化,那么就想到了时间,时间是每秒都在变化的,可以让时间来充当种子参数

  

int main() {
    srand((int)time(NULL)); // #include<ctime> for time()
    for (int i = 0; i < 10; i++) {
        cout << rand() << "\t";
    }
    return 0;
}

  输出结果:

    31937   9951    11817   1295    252     30339   22649   12202   9420    16246

  与之前结果不同了。似乎这达到了我们获取真随机数的目的。但是依旧有一个问题,那就是time 是以秒为单位的,如果你的项目要在一秒之内调用多次随机数呢?这样一来,种子在这一秒之内是不会发生变化的。

int getrd_1() {
    srand((int)time(NULL)); // #include<ctime> for time()
    return rand();
}

int main() {
    for (int i = 0; i < 10; i++) {
        cout << getrd_1() << "\t";
    }
    return 0;
}

   输出结果:

      32753   32753   32753   32753   32753   32753   32753   32753   32753   32753

    果然是一样的,因为这十次调用都是在1秒之内。

    这种情况下,可以使用random_device 来生成真随机数

    

int getrd(const int &min, const int&max) {//范围 [min,max)
    std::random_device rd;                //#include<random> for std::random_device
    return min + rd() % max;
}
int main() {
    for (int i = 0; i < 10; i++)
        std::cout << getrd(0, 10) << "\t";
    return 0;
}

    输出结果:

        3       0       0       9       7       8       5       4       9       2

    达到了我们预期的要求。

    但是,需要注意,这个实现要看你的库支持不支持,如果不支持,将继续使用伪随机数发生器。可以通过调用random_device的成员函数 entropy()来查看熵,如果是伪随机发生器,熵恒为零

  • swap

    

//通过一个临时变量来储存b的值,完成交换
void swap(int &a, int &b) {
    int tmp(b);
    b = a;
    a = tmp;
}
//通过异或^来完成交换
void swap(int &a, int &b) {
    if (a == b)
        return;
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
}

    第一种交换司空见惯了,第二种则用到了位操作 异或 ^ 的性质:

            a ^ 0 等于 a                           a ^ a 等于 0 

            满足结合律,交换律

    因此:

        第一句:a = a ^ b ;   第二句:b = a ^ b,此时 b 等于 a^b^b,结合性质 结果是 a  ; 第三句 : a = a ^ b ,此时 a等于 a ^ b ^ a,结果是b ,交换完成

    需要注意的是,如果a 与  b 的地址相同 则 a^b 等于0。

最后贴上我的快排:

 

class Solution {
private:
    void swap(int& a, int& b) {
        if (a == b)
            return;
        a = a ^ b;
        b = a ^ b;
        a = a ^ b;
    }
    int getrd(const int &min,const int& max) {
        random_device rd;
        return min + rd() % (max - min);
    }
public:
    //快排
    int* Mypartition(vector<int>& nums, int L, int R) {
        int less(L - 1), more(R);
        int i(L);
        while (i < more) {
            if (nums[i] < nums[R]) {
                swap(nums[++less], nums[i++]);
            }
            else if (nums[i] > nums[R]) {
                swap(nums[i], nums[--more]);
            }
            else
                i++;
        }
        swap(nums[more], nums[R]);
        return new int [2]{ less, more+1 };
    }
    void process(vector<int>& nums, int L, int R) {
        if (L < R) {
            // cout<<"L ="<<L<<"\t R="<<R<<endl;
            swap(nums[getrd(L,R)], nums[R]);
            int *p = Mypartition(nums,L,R);
            process(nums, L, p[0]);
            process(nums, p[1], R);
        }
    }
    vector<int> sortArray(vector<int>& nums) {
        process(nums, 0, nums.size()-1);
        return nums;
    }
};

 

标签:return,nums,int,C++,快排,32753,swap,随机数
From: https://www.cnblogs.com/xhzg/p/16630883.html

相关文章

  • java产生一个随机数
    //随机产生8位数StringBuilderstr=newStringBuilder();//定义变长字符串Randomrandom=newRandom();//随机生成数字,并添加到字符串for(inti=0;i<8;i++){str.a......
  • ACM模式各种输入总结 C++
    一、整型数组输入:(很简单)在终端的一行中输入固定数目的整型数字,并存到数组中,中间以空格分隔。示例:3123intn;cin>>n;vector<int>nums(n);......
  • vscode环境配置(C/C++)
    一.MinGW和vscode的简单了解1.MinGW是什么?MinGW(MinimalistGNUonWindows)。它实际上是将经典的开源C语言编译器GCC移植到了Windows下,并且包含了Win32API,因此可......
  • c++知识点速刷
    语法指针和引用指针:存放某个对象的地址引用:变量的别名,从一而终,不可变,必须初始化const变量指针常量(底层const):指针所指的对象不可变常量指针(顶层const):指针不可变defin......
  • 强化学习——价值迭代算法 悬崖漫步为例 C++
    #include<bits/stdc++.h>usingnamespacestd;#defineN100#definecliffcliff_mapintrow,col;structState{intnext_i,next_j,flag;doublereward;......
  • vc++ get random via random_device,mt19937
     #include<ctime>#include<iostream>#include<random>usingnamespacestd;staticrandom_devicerd;staticmt19937mt{rd()};template<typenameT>vo......
  • [C++]类名加个括号是什么东东
    先考考大家,下面的代码,编译得过吗?classMyClass{public:MyClass(){printf("MyClass\n");}};int_tmain(intargc,_TCHAR*argv[]){......
  • 快速排序,快排的一次分解及递归完整快排
    本篇讲解的是Lomuto快排的一个衍生算法,就是基准数取的是数组的第一个元素首先是快排中的一次执行过程的理解,本次取的是最初的一次,将数组的第一个元素【4】放置到它该去的......
  • Java调用C++动态链接库——Jni
    最近项目需要,将C++的算法工程编译成动态链接库,交给Java后台当作函数库调用。就去了解了下Jni。使用起来还是比较方便的。1.  首先编写Java的调用类。例如:  public......
  • 记刷题过程中发现的C++与C的差异
    前言上大学了,学c。标题嫖自@快乐永恒正题01#include<stdio.h>intmain(){longlonga,b;scanf("%lld%lld",&a,&b);printf("%lld%lld%lld%lld%l......