A few days ago in the Mushroom Street interview encountered a shuffling algorithm problem, take out and share with you!
The original question is: 54 ordered cards, how disorderly to send 3 people?
The problem is to use the classic shuffle algorithm to complete. First, a classic shuffling algorithm--fisher-yates is introduced. Now everyone on the internet to see, mostly fisher-yates algorithm deformation. The original O (N2) is simplified to O (n). The code is as follows:
#include <stdio.h> #include <stdlib.h>void func (char *, int), void Main () { char a[7] = {' A ', ' B ', ' C ', ' d ', ' E ', ' f '}; Func (a,6); A[7] = ' + '; Puts (a);} void func (char *date, int length) { char t; T for exchanging character space int i, J; while (--length) { srand (time (0)); i = rand ()% (length+1); t = date[i]; Date[i] = date[length]; Date[length] = t; }}
The idea of the algorithm is:
A, select the last position that is not operational, and generate a random number between 1 and the position (including both values).
b, and then swapping the two values, the result is to randomly take one of the unused cards to the bottom of the length-1 (the end of the array), and then subtract one from the operating range,
C, repeat the above steps until the value of the operation is 1 stop
The code is very clear and easy to write. There are many ways to do it online. But through a lot of tests, can give affirmation, the improved fisher-yates algorithm, that is, the above code, is already a good shuffle algorithm. That is, simple, random and good. So if you give the above answer in an interview, you can basically do the next question. If the interviewer doesn't think it's enough. Can be from the integrity and robustness of the Code (sword refers to the offer of specific practices), such as the correctness of parameters, encountered invalid input and other aspects of improvement. or optimize random values.
We can also mention a little bit more about optimizing random values.
The first thing to be sure is that the random number in a computer is not really a random number, it is a pseudo-random number, is a random number calculated by some formula, by changing the value of the parameters in the equation to achieve a random effect. Although it is a pseudo-random number, it can actually meet the requirements of our programming.
There are 4 functions for generating random numbers in C, with 22 used:
int rand (void); Returns an int type integer between 0-------Rand_max, which is a non-thread-safe function. And the performance of generating random numbers is not very good, it is deprecated.
void Srand (unsigned int seed); Sets the seed value, which is typically the seed of "current time + process ID", and if this function is not called, the default seed value returned by Rand is 1.
long int random (void); Returns a long integer between 0-------Rand_max that produces a very large random value up to 16* ((2**31)-1).
The random function generates a continuous pseudo-random number returned by a default size of 31 long integer tables using a nonlinear feedback stochastic number generator.
void srandom (unsigned int seed); Set the seed value, typically with "current time + process ID" as the seed, if the function is not called, the default seed value returned by random is 1.
The above four functions are the functions that the C language uses to generate random numbers.
If you are planting seeds using srandom, then you should use random to return the numbers, and if you use srand to grow the seeds, you should use Rand to return random numbers.
However, Srand and RAND officials have not recommended it. The reason is that the performance of random numbers is not very good, and the randomness of random numbers is not good, and the other is not thread safety.
As for Rand's thread is unsafe, if you look at its source code under Linux, this sentence is easy to understand.
/*These two functions are programs that generate random numbers in the C library. You need to use the Srand () function to assign a random number seed value first. The rand () function is then used to generate a random number. However, the algorithm for generating random numbers is simpler, and the Srandom () and random () functions are improved for these two functions and are similar in usage. */#defineRandom_max 0x7FFFFFFFStatic LongMy_do_rand (unsignedLong*value) { /*This algorithm guarantees that the resulting value will not exceed (2^31-1) here (2^31-1) is 0x7FFFFFFF. and 0x7FFFFFFF equals 127773 * (7^5) + 2836,7^5 = 16807. The entire algorithm is calculated by using the formula T = (7^5 * t) mod (2^31-1) to calculate the random value, and the resulting value as the random seed value for the next calculation. */ Longquotient, remainder, t; Quotient= *value/127773L; Remainder= *value%127773L; T=16807L* Remainder-2836L*quotient; if(T <=0) T+=0X7FFFFFFFL; return((*value = t)% ((unsignedLong) Random_max +1));}StaticUnsignedLongNext =1;intMy_rand (void){ returnMy_do_rand (&next);} voidMy_srand (unsignedintseed) {Next=seed;}
It is clear from the code that the Srand () function assigns a parameter to a global variable, which is why Srand () uses the int parameter and does not return a value that can affect Rand (). Srand () After modifying the value of Next, the rand () function may implicitly invoke the parameter (indirect invocation). See here, you can understand why it is a thread unsafe function, if in a multi-threading operation, a thread line call Srand, and then not complete when another thread modifies the next, the operation is meaningless, this is the basic multithreaded programming process synchronization and mutual exclusion. The improvement of random () is based on this. In addition, we can see that the return value of rand () is calculated based on a function similar to y=ax+b. In this expression, a, B is a constant value, and the x here is a random seed, which is the seed that is modified by Srand ().
The last point to mention is:
If you want to generate a random number between 1------10, it is recommended that you encode as follows
j = 1 + (int) (10.0 * (rand ()/(Rand_max + 1.0));
Instead of code like the following
j = 1 + (rand ()% 10);
The advantage of the first line of code is that the real type is used instead of shaping, the data is continuous, so the stochastic is more uniform, thus increasing randomness.
If you want to generate a random number of 1-8, j = 1 + (int) (8.0 * (rand ()/(Rand_max + 1.0)); Can
1-x: j = 1 + (int) (x.0 * (rand ()/(Rand_max + 1.0)); Can
Shuffle algorithm fisher-yates and the generation of C language random numbers