C++ minimax function - c++

I have searched Google and Stackoverflow for this question, but I still don't understand how a minimax function works.
I found the wikipedia entry has a pseudocode version of the function:
function integer minimax(node, depth)
if node is a terminal node or depth <= 0:
return the heuristic value of node
α = -∞
for child in node: # evaluation is identical for both players
α = max(α, -minimax(child, depth-1))
return α
Several other minimax functions I found with Google are basically the same thing; I'm trying to implement this in C++, and this is what I have come up with so far:
double miniMax(Board eval, int iterations)
{
//I evaluate the board from both players' point of view and subtract the difference
if(iterations == 0)
return boardEval(eval, playerNumber) - boardEval(eval, opponentSide());
/*Here, playerTurn tells the findPossibleMoves function whose turn it is;
I mean, how do you generate a list of possible moves if you don't even know
whose turn it's supposed to be? But the problem is, I don't see where I can
get playerTurn from, as there are only 2 parameters in all the examples of
minimax I've seen*/
vector<int> moves = eval.findPossibleMoves(playerTurn);
//I'm assuming -∞ in the wikipedia article means a very low number?
int result = -999999999;
//Now I run this loop to evaluate each possible move
/*Also, the Lua example in the wiki article has
alpha = node.player==1 and math.max(alpha,score) or math.min(alpha,score)
Is alpha a boolean there?!*/
for(int i = 0; i * 2 < moves.size(); i++)
{
//I make a copy of the board...
Board temp = eval;
/*and make the next possible move... once again playerTurn crops up, and I
don't know where I can get that variable from*/
temp.putPiece(moves[i * 2], moves[i * 2 + 1], playerTurn);
/*So do I create a function max that returns the bigger of two doubles?*/
result = max(result, -miniMax(temp, iterations - 1));
}
return result;
/*So now I've returned the maximum score from all possible moves within a certain
# of moves; so how do I know which move to make? I have the score; how do I know
which sequence of moves that score belongs to?*/
}
As you can see, I'm pretty confused about this minimax function. Please at the very least give me some hints to help me with this.
Thanks! :)

That sample from Wikipedia is doing NegaMax with Alpha/Beta pruning.
You may be helped by getting the naming straight:
The basis is MiniMax, a literal implementation would involve 2 methods that take turns (mutually recursive), 1 for each side.
Lazy programmers turn this into NegaMax, one method with a strategically placed - operator.
Alpha/Beta pruning is keeping track of a Window of best moves (over multiple depths) to detect dead branches.
Your playerTurn is used to determine whose turn it is . In NegaMax you can derive this from the depth (iterations) being odd or even. But it would be easier to use 2 parameters (myColor, otherColor) and switch them at each level.

Your miniMax() function should remember the best move it found so far. So instead of this code:
/*So do I create a function max that returns the bigger of two doubles?*/
result = max(result, -miniMax(temp, iterations - 1));
You should do something like this:
/*So do I create a function max that returns the bigger of two doubles?*/
double score = -miniMax(temp, iterations - 1);
if (score > result)
{
result = score;
bestMove = i;
}
Of course, you need a variable "bestMove" and a way to return the best move found to the caller.

Add the playerTurn variable as an argument to miniMax, and call miniMax which the current player's move initially and recursively.
Also, opponentSide needs to be a function of playerTurn.

A good place to start with game tree searching is the chess programming wiki. For your question about the move: I think it is most common to have two max-functions. The difference between the two max functions is that one returns only the score and the other returns the score and the best move. A recursive call order would be like following:
maxWithBestMoveReturn(...) --> min(...) --> max(...) --> min(...)
There are some good papers with pseudocode for the Alpha Beta algorithm:
TA Marsland - Computer Chess and Search
J Schaeffer - The games Computers (and People) Play
To your question in the comment: and math.max(alpha,score) or math.min(alpha,score) Is alpha a boolean there?!
No alpha is a window bound in a alpha beta algorithm. The alpha value gets updated with a new value. Because alpha and beta are swapped with the recursive call of the negamax-Function the alpha variable refers to the beta variable in the next recursive call.
One note to the playerTurn variable: The minimax or alpha-beta algorithm doesn't need this information. So i would give the information -- who's next --, into the Board-Structure. The functions findPossibleMoves and boardEval get all information they need from the Board-Structure.
One note to the recursive break condition: If i understand your code right, then you only have the one with iterations == o. I think this means the algorithm has reached the desired depth. But what if there are no possible moves left befor the algorithm reaches this depth. Maybe you should write following:
vector<int> moves = findPossibleMoves(...);
if (!moves.size())
return boardEval(...);

In your pseudocode, the node variable has to contain all the information about the current board position (or whatever). This information would include whose turn it is to move.

Related

print all the triplets (3 Sum) leetcode,https://leetcode.com/problems/3sum/ [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
Improve this question
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<int> v;
vector<vector<int>> ans;
int n=nums.size();
sort(nums.begin(),nums.end());
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
for(int k=j+1;k<n;k++){
if(nums[i]+nums[j]+nums[k]==0 && i!=j && i!=k && j!=k){
v.push_back(nums[i]);
v.push_back(nums[j]);
v.push_back(nums[k]);
ans.push_back(v);
}
}
}
}
return ans;
}
};
it is not showing an error but it is displaying wrong answer as i have given in the attachment
Input: [-1, 0, 1, 2, -1, 4]
Your output: [[-1, -1, 2], [-1, -1, 2, -1, 0, 1], [-1, -1, 2, -1, 0, 1, -1, 0, 1]]
Expected output: [[-1, -1, 2], [-1, 0, 1]]
I can understand the problem with pushing back more and more values the my vector v. OK.
But maybe, somebody could give me a hint on how to tackle the problem with the duplicates?
Any help for me as a new user is highly welcome and appreciated.
Of course, we will help you here on SO.
Starting with a new language is never that easy and there may by some things that are not immediately clear in the beginning. Additionally, I do apologize for any rude comments that you may see, but you can be assured that the vast majority of the members of SO are very supportive.
I want to first give you some information on pages like Leetcode and Codeforces and the like. Often also referred to as “competitive programming” pages. Sometimes people misunderstand this and they think that you have only a limited time to submit the code. But that is not the case. There are such competitions but usually not on the mentioned pages. The bad thing is, the coding style used in that real competition events is also used on the online pages. And that is really bad. Because this coding style is that horrible that no serious developer would survive one day in a real company who needs to earn money with software and is then liable for it.
So, these pages will never teach you or guide you how to write good C++ code. And even worse, if newbies start learning the language and see this bad code, then they learn bad habits.
But what is then the purpose of such pages?
The purpose is to find a good algorithm, mostly optimized for runtime execution speed and often also for low memory consumption.
So, the are aiming at a good design. The Language or coding style does not matter for them. So, you can submit even completely obfuscated code or “code golf” solutions, as long at is it fast, it does not matter.
So, do never start to code immediately as a first step. First, think 3 days. Then, take some design tool, like for example a piece of paper, and sketch a design. Then refactor you design and then refactor your design and then refactor your design and then refactor your design and then refactor your design and so one. This may take a week.
And next, search for an appropriate programming language that you know and can handle your design.
And finally, start coding. Because you did a good design before, you can use long and meaningful variable names and write many many comments, so that other people (and you, after one month) can understand your code AND your design.
OK, maybe understood.
Now, let’s analyze your code. You selected a brute force solution with a triple nested loop. That could work for a low number of elements, but will result in most cases in a so called TLE (Time Limit Exceeded) error. Nearly all problems on those pages cannot be solved with brute force. Brute force solutions are always an indicator that you did not do the above design steps. And this leads to additional bugs.
Your code has too major semantic bugs.
You define in the beginning a std::vector with the name “v”. And then, in the loop, after you found a triplet meeting the given condition, you push_back the results in the std::vector. This means, you add 3 values to the std::vector “v” and now there are 3 elements in it. In the next loop run, after finding the next fit, you again push_back 3 additional values to your std::vector ”v” and now there are 6 elements in it. In the next round 9 elements and so on.
How to solve that?
You could use the std::vector’s clear function to delete the old elements from the std::vector at the beginning of the most inner loop, after the if-statement. But that is basically not that good, and, additionally, time consuming. Better is to follow the general idiom, to define variables as late as possible and at that time, when it is needed. So, if you would define your std::vector ”v” after the if statement, then the problem is gone. But then, you would additionally notice that it is only used there and nowhere else. And hence, you do not need it at all.
You may have seen that you can add values to a std::vector by using an initializer list. Something like:
std::vector<int> v {1,2,3};
With that know-how, you can delete your std::vector “v” and all related code and directly write:
ans.push_back( { nums[i], nums[j], nums[k] } );
Then you would have saved 3 unnecessary push_back (and a clear) operations, and more important, you would not get result sets with more than 3 elements.
Next problem. Duplicates. You try to prevent the storage of duplicates by writing && i!=j && i!=k && j!=k. But this will not work in general, because you compare indices and not values and because also the comparison is also wrong. The Boolean expressions is a tautology. It is always true. You initialize your variable j with i+1 and therefore “i” can never be equal to “j”. So, the condition i != j is always true. The same is valid for the other variables.
But how to prevent duplicate entries. You could do some logical comparisons, or first store all the triplets and later use std::unique (or other functions) to eliminate duplicates or use a container that would only store unique elements like a std::set. For the given design, having a time complexity of O(n^3), meaning it is already extremely slow, adding a std::set will not make things worse. I checked that in a small benchmark. So, the only solution is a completely different design. We will come to that later. Let us first fix the code, still using the brute force approach.
Please look at the below somehow short and elegant solution.
vector<vector<int>> threeSum(vector<int>& nums) {
std::set<vector<int>> ans;
int n = nums.size();
sort(nums.begin(), nums.end());
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++)
for (int k = j + 1; k < n; k++)
if (nums[i] + nums[j] + nums[k] == 0)
ans.insert({ nums[i], nums[j], nums[k] });
return { ans.begin(), ans.end() };
}
But, unfortunately, because of the unfortunate design decision, it is 20000 times slower for big input than a better design. And, because the online test programs will work with big input vectors, the program will not pass the runtime constraints.
How to come to a better solution. We need to carefully analyze the requirements and can also use some existing know-how for similar kind of problems.
And if you read some books or internet articles, then you often get the hint, that the so called “sliding window” is the proper approach to get a reasonable solution.
You will find useful information here. But you can of course also search here on SO for answers.
for this problem, we would use a typical 2 pointer approach, but modified for the specific requirements of this problem. Basically a start value and a moving and closing windows . . .
The analysis of the requirements leads to the following idea.
If all evaluated numbers are > 0, then we can never have a sum of 0.
It would be easy to identify duplicate numbers, if they would be beneath each other
--> Sorting the input values will be very beneficial.
This will eliminate the test for half of the values with randomly distribute input vectors. See:
std::vector<int> nums { 5, -1, 4, -2, 3, -3, -1, 2, 1, -1 };
std::sort(nums.begin(), nums.end());
// Will result in
// -3, -2, -1, -1, -1, 1, 2, 3, 4, 5
And with that we see, that if we shift our window to the right, then we can sop the evaluation, as soon as the start of the window hits a positive number. Additionally, we can identify immediately duplicate numbers.
Then next. If we start at the beginning of the sorted vector, this value will be most likely very small. And if we start the next window with one plus the start of the current window, then we will have “very” negative numbers. And to get a 0 by summing 2 “very” negative numbers, we would need a very positive number. And this is at the end of the std::vector.
Start with
startPointerIndex 0, value -3
Window start = startPointerIndex + 1 --> value -2
Window end = lastIndexInVector --> 5
And yes, we found already a solution. Now we need to check for duplicates. If there would be an additional 5 at the 2nd last position, then we can skip. It will not add an additional different solution. So, we can decrement the end window pointer in such a case. Same is valid, if there would be an additional -2 at the beginning if the window. Then we would need to increment the start window pointer, to avoid a duplicate finding from that end.
Some is valid for the start pointer index. Example: startPointerIndex = 3 (start counting indices with 0), value will be -1. But the value before, at index 2 is also -1. So, no need to evaluate that. Because we evaluate that already.
The above methods will prevent the creation of duplicate entries.
But how to continue the search. If we cannot find a solution, the we will narrow down the window. This we will do also in a smart way. If the sum is too big, the obviously the right window value was too big, and we should better use the next smaller value for the next comparison.
Same on the starting side of the window, If the sum was to small, then we obviously need a bigger value. So, let us increment the start window pointer. And we do this (making the window smaller) until we found a solution or until the window is closed, meaning, the start window pointer is no longer smaller than the end window pointer.
Now, we have developed a somehow good design and can start coding.
We additionally try to implement a good coding style. And refactor the code for some faster implementations.
Please see:
class Solution {
public:
// Define some type aliases for later easier typing and understanding
using DataType = int;
using Triplet = std::vector<DataType>;
using Triplets = std::vector<Triplet>;
using TestData = std::vector<DataType>;
// Function to identify all unique Triplets(3 elements) in a given test input
Triplets threeSum(TestData& testData) {
// In order to save function oeverhead for repeatingly getting the size of the test data,
// we will store the size of the input data in a const temporary variable
const size_t numberOfTestDataElements{ testData.size()};
// If the given input test vector is empty, we also immediately return an empty result vector
if (!numberOfTestDataElements) return {};
// In later code we often need the last valid element of the input test data
// Since indices in C++ start with 0 the value will be size -1
// With taht we later avoid uncessary subtractions in the loop
const size_t numberOfTestDataElementsMinus1{ numberOfTestDataElements -1u };
// Here we will store all the found, valid and unique triplets
Triplets result{};
// In order to save the time for later memory reallocations and copying tons of data, we reserve
// memory to hold all results only one time. This will speed upf operations by 5 to 10%
result.reserve(numberOfTestDataElementsMinus1);
// Now sort the input test data to be able to find an end condition, if all elements are
// greater than 0 and to easier identify duplicates
std::sort(testData.begin(), testData.end());
// This variables will define the size of the sliding window
size_t leftStartPositionOfSlidingWindow, rightEndPositionOfSlidingWindow;
// Now, we will evaluate all values of the input test data from left to right
// As an optimization, we additionally define a 2nd running variable k,
// to avoid later additions in the loop, where i+1 woild need to be calculated.
// This can be better done with a running variable that will be just incremented
for (size_t i = 0, k = 1; i < numberOfTestDataElements; ++i, ++k) {
// If the current value form the input test data is greater than 0,
// As um with the result of 0 will no longer be possible. We can stop now
if (testData[i] > 0) break;
// Prevent evaluation of duplicate based in the current input test data
if (i and (testData[i] == testData[i-1])) continue;
// Open the window and determin start and end index
// Start index is always the current evaluate index from the input test data
// End index is always the last element
leftStartPositionOfSlidingWindow = k;
rightEndPositionOfSlidingWindow = numberOfTestDataElementsMinus1;
// Now, as long as if the window is not closed, meaning to not narrow, we will evaluate
while (leftStartPositionOfSlidingWindow < rightEndPositionOfSlidingWindow) {
// Calculate the sum of the current addressed values
const int sum = testData[i] + testData[leftStartPositionOfSlidingWindow] + testData[rightEndPositionOfSlidingWindow];
// If the sum is t0o small, then the mall value on the left side of the sorted window is too small
// Therefor teke next value on the left side and try again. So, make the window smaller
if (sum < 0) {
++leftStartPositionOfSlidingWindow;
}
// Else, if the sum is too biig, the the value on the right side of the window was too big
// Use one smaller value. One to the left of the current closing address of the window
// So, make the window smaller
else if (sum > 0) {
--rightEndPositionOfSlidingWindow;
}
else {
// Accodring to above condintions, we found now are triplet, fulfilling the requirements.
// So store this triplet as a result
result.push_back({ testData[i], testData[leftStartPositionOfSlidingWindow], testData[rightEndPositionOfSlidingWindow] });
// We know need to handle duplicates at the edges of the window. So, left and right edge
// For this, we remember to c
const DataType lastLeftValue = testData[leftStartPositionOfSlidingWindow];
const DataType lastRightValue = testData[rightEndPositionOfSlidingWindow];
// Check left edge. As long as we have duplicates here, we will shift the opening position of the window to the right
// Because of boolean short cut evaluation we will first do the comparison for duplicates. This will give us 5% more speed
while (testData[leftStartPositionOfSlidingWindow] == lastLeftValue && leftStartPositionOfSlidingWindow < rightEndPositionOfSlidingWindow)
++leftStartPositionOfSlidingWindow;
// Check right edge. As long as we have duplicates here, we will shift the closing position of the window to the left
// Because of boolean short cut evaluation we will first do the comparison for duplicates. This will give us 5% more speed
while (testData[rightEndPositionOfSlidingWindow] == lastRightValue && leftStartPositionOfSlidingWindow < rightEndPositionOfSlidingWindow)
--rightEndPositionOfSlidingWindow;
}
}
}
return result;
}
};
The above solution will outperform 99% of other solutions. I made many benchmarks to prove that.
It additionally contains tons of comments to explain what is going on there. And If I have selected “speaking” and meaningful variable names for a better understanding.
I hope, that I could help you a little.
And finally: I dedicate this answer to Sam Varshavchik and PaulMcKenzie.

When should an evaluation function for the minimax algorithm return negative values?

I have an evaluation function for a connect four type game. I don't understand when the evaluation function is suppose to give negative values. My evaluation function basically assigns a value for each move psuedocode might be easier to show
if player has 4 in a row
return 5000;
if player has 3 in a row
return 4000;
if opponent has 3 in a row or 3 in a column
return 4000;
if opponent a disjoint 3 in a row or column //ie xx x
return 4000;
if opponent has in row with spaces on both sides// ie ' 'OO' '
return 100;
if opponent has two in arrow w/o spaces on both sides // ie XOO
return 95;
This is the basic idea, however since there are no negative values, the min function always returns 0;
What am I missing here?
First off, your evaluation function does not have to ever give negative values. That is only a convention for simplicity that moves good for player one are positive, good for player two are negative, and equally good are zero. That should not cause your min function to return zero. If you post your min function, perhaps we can help you. My suspicion from personal experience (I made a connect four engine too) is that the min function sets the default value to zero. That will only work for the max function. The min funcion default must be set to a very high number (in the case of your evaluation numbers 5000). Otherwise, all moves it looks at will never beat zero. Just a guess

sudoku recursion: exactly where and how does the backtracking occur?

I am working on writing my own Sudoku Code in c++ with a few requirements for an assignment. It must use recursion and a vector of vectors. I think I generally understand the c++ language part but I do not get logic in part of the backtrack process. My pseudocode will pass my i,j position to other functions in another class as well as the value k(choice of 1-9). Let's say I am 3 iterations in my solve, I reach a square for which I have checked all values 1-9 and none of them work. Now I set this to zero and have to backtrack,and go to the previous square/iteration I worked on and try a different value to proceeded with, come back to the square I was on and check again.
My exact question is this: Where in my code can there be this move back to the previous square? I am not seeing how to fit this in or how this works in these loops? If I don't go back one, then my code will find the same square again and run through all 9 choices, fail, and go back again in an infinite recursion? I am terrified to start testing runs of this code for fear of infinite recursive loops. My pseudocode is as follows:
bool Board::solveBoard()
{
Board board;
if(board.isComplete())
{
board.display();
return true;
}
for(int i=ZERO;i<NINE;++i)//iterate through row vectors
{
for (int j=ZERO;j<NINE;++j)//iterate through column vectors
{
if(board.getSquare(i,j)==ZERO)//find first value equal to zero
{
for(int k=ONE;k<=NINE;++k)//iterate through values 1-9 to fill square and check board
{
board.setSquare(i,j,k);//assign k=1 to 9
if(board.isLegal(i,j,k))//check if value is legal
{
if(solveBoard) return true;
}
board.unsetSquare(i,j);//otherwise remove value in backtracking?
}//end # 1-9 iteration
}//end get square-check square loop
return false;//I think this is where the program will go back a step to the last value worked previously
}//end column iteration
}//end row iteration
} // bool Board::solveBoard()
The notation ZERO, NINE etc is a requirement by the instructor as "magic numbers" to be capitalized. I have read that infinite recursion can fill up computer memory and crash it so that is why I was worried. I am just trying to identify where the backtracking to previous step actually occurs?I put a return false towards the bottom that will return false in the column iteration. Will this then tell the iteration to go back to the previous j value and try again- and how will it fill it with a different number other than starting with the number one just like it did before?

simple hash map with vectors in C++

I'm in my first semester of studies and as a part of my comp. science assignment I have to implement a simple hash map using vectors, but I have some problems understanding the concept.
First of all I have to implement a hash function. To avoid collisions I thought it would be better to use double hashing, as follows:
do {
h = (k % m + j*(1+(k % (m-2)));
j++;
} while ( j % m != 0 );
where h is the hash to be returned, k is the key and m is the size of hash_map (and a prime number; they are all of type int).
This was easy, but then I need to be able to insert or remove a pair of key and the corresponding value in the map.
The signature of the two functions should be bool, so I have to return either true or flase, and I'm guessing that I should return true when there is no element at position h in the vector. (But I have no idea why remove should be bool as well).
My problem is what to do when the insert function returns false (i.e. when there is already a key-value pair saved on position h - I implemented this as a function named find). I could obviously move it to the next free place by simply increasing j, but then the hash calculated by my hash function wouldn't tell us anymore at which place a certain key is saved, causing wrong behaviour of remove function.
Is there any good example online, that doesn't use the pre defined STD methods? (My Google behaves wierdly in the past few days and only reutrns me unuseful hits in the local language)
I've been told to move my comment to an answer so here it is. I am presuming your get method takes the value you are looking for an argument.
so what we are going to do is a process called linear probing.
when we insert the value we hash it as normal lets say our hash value is 4
[x,x,x,,,x,x]
as we can see we can simply insert it in:
[x,x,x,x,,x,x]
however if 4 is taken when we insert it we will simply move to the next slot that is empty
[x,x,x,**x**,x,,x,x]
In linear probing if we reach the end we loop back round to the beginning until we find a slot. You shouldn't run out of space as you are using a vector which can allocate extra space when it starts getting near full capacity
this will cause problems when you are searching because the value at 4 may not be at 4 anymore (in this case its at 5). To solve this we do a little bit of a hack. Note that we still get O(1) run time complexity for inserting and retrieval as long as the load balance is below 1.
in our get method instead of returning the value in the array at 4 we are instead going to start looking for our value at 4 if its there we can return it. If not we look at the value at 5 and so on till we find the value.
in psudo code the new stuff looks like this
bool insert(value){
h = hash(value);
while(node[h] != null){
h++;
if( h = node.length){
h = 0;
}
}
node[h] = value;
return true;
}
get
get(value){
h = hash(value);
roundTrip = 0; //used to see if we keep going round the hashmap
while(true){
if(node[h] == value)
return node[h];
h++;
if( h = node.length){
h = 0;
roundTrip++;
}
if(roundTrip > 1){ //we can't find it after going round list once
return -1;
}
}
}

What is a good example of recursion other than generating a Fibonacci sequence?

Locked. This question is not currently accepting new answers or interactions. Learn more.
Possible Duplicates:
Real-world examples of recursion
Examples of Recursive functions
I see that most programming language tutorial teach recursion by using a simple example which is how to generate fibonacci sequence, my question is, is there another good example other than generating fibonacci sequence to explain how recursion works?
The classic is the binary tree search:
def findval (node,val):
if node == null:
return null
if node.val = val:
return node
if node.val > val:
return findval (node.left,val)
return findval (node.right,val)
findval (root,thing_to_find)
That may be a little more complex than a simple formula but it's the "bread and butter" use of recursion, and it illustrates the best places to use it, that where the recursion levels are minimised.
By that I mean: you could add two non-negative numbers with:
def add (a,b):
if b == 0:
return a
return add (a+1,b-1)
but you'd find yourself running out of stack space pretty quickly for large numbers (unless the compiler optimised tail-end recursions of course, but you should probably ignore that for the level of teaching you're concerned with).
The other answers mention various algorithms, which is completely fine, but if you want a bit more "concrete" example, you could list all files in some directory and its subdirectories. The hierarchical file system is a well-known example of a recursive (tree) structure, and you could show depth-first and breadth-first search using this concrete example.
My favourite example for recursion is the Towers of Hanoi: To move a stack of pieces from pole A to pole B, you move everything above the lowest piece to the pole that is not A or B, then move the lowest piece to B, and then you move the stack that you put on the "helper pole" on top of the lowest piece. For the first and third step, you follow this instruction recursively. See the link for a longer explanation :)
Check for a palyndrome:
bool recursivePalindrome(std::string str, unsigned int index = 0) {
if (index > str.length()/2) return true;
else if (str[index] == str[str.length()-index-1])
return recursivePalindrome(str, ++index);
else return false;
}
Or on a less serious note :)
void StackOverflow()
{
StackOverflow();
}
How about finding factorial.
int GetFactorial(int n )
{
if ( n==0) return 1;
return n*GetFactorial(n-1);
}
The idea is, factorial is defined recursively as the product of n and factorial of (n-1). And from recursive definition, you get your recursion.
Traversing the folder hierarchy of a directory tree as part of a file system is a good real-world example. Look into this SO post for a C++ example:
Why am I having problems recursively deleting directories?
Most of the other examples given here are mathematics examples which really just re-illustrate the same application of recursion.
The search and sort variants are good algorithm examples but often a bit too complicated for beginners.
Towers of Hanoi is a classic but pretty contrived really.
================
The example I use for demonstrating the simple power of recursion is recursive file processing in a directory tree.
Here is a C# example
void ProcessFiles( string sFolder )
{
foreach( string f in Directory.GetFiles( sFolder ) )
{
DoSomethingTo( f );
}
foreach( string d in Directory.GetDirectories( sFolder ))
{
ProcessFiles( d );
}
}
Merge sort is a pretty good example of an algorithm that is easier to read and understand when implemented recursively.
Here's a little high-level pseudocode version of Merge Sort:
def merge_sort(List sortlist)
if sortlist.length <= 1 return sortlist
split sortlist into leftlist and rightlist
return merge(merge_sort(leftlist), merge_sort(rightlist))
def merge(List leftlist, List rightlist)
while(leftlist and rightlist not empty)
compare leftlist.first to rightlist.first
pop lowest value off its list and append to resultlist
append any remains of leftlist onto resultlist
append any remains of rightlist onto resultlist
return resultlist
An iterative version of this is would be much more complicated to write and to visualise.
There are several samples:
Catalan numbers:
T(n) = Sum(T(i)*T(n-i)) for all 1 <= i < n
Ackermann function:
A(x,y) = y+1 (if x = 0)
A(x,y) = A(x-1,1) (if y=0)
A(x,y) = A(x-1, A(x,y-1)) otherwise.
Simple Maze problem
Finding Hamiltonian Path problem
factorial.
and you can see wiki page for other references.
Good examples of recursion are often related to cases where underlying data structure or the problem itself is recursive : trees, graphs, algorithms using divide and conquer approach (like many sorts), parser of recursive grammars (like common arithmetic expresions), find strategy for chess-like two players games (for a simple exemple consider Nim), combinatory problems, etc.
Try recursive binary search:
http://www.fredosaurus.com/notes-cpp/algorithms/searching/rbinarysearch.html
Or a recursive quick sort:
http://www.dreamincode.net/forums/topic/72311-recursive-quicksort-algorithm/
These are just two small example in a vast world of recursive functions.
Evaluation of arithmetic expressions can be done recursively or iteratively using a stack. It can be quite instructive to compare the two approaches.
My mother-in-law took an introductory course in C. She had a homework problem, something like:
You have a bar of metal (length len), and a number
of orders (n) to cut the metal into
various lengths. You want to maximize
the amount of metal being used, but
cannot exceed the overall length.
The instructor suggested iterating from 1 to 2**n in binary, excluding an order if its corresponding bit were 0 and including an order if its bit were 1, while keeping track of the maximum sum. His proposal would run in polynomial time.
Another solution exists using a recursive knapsack algorithm. You can iterate down from len to 1 and do a depth-first search to recursively find the sum of lengths.
A different area in which I have used recursion was for Huffman coding (for compressing a string), but this does not have the intuitive feel of the knapsack problem.
Recursion is a wonderful concept that is radically different. Best wishes in learning or teaching it.
Ackermann function:
/* undefined if m and n are negative */
uint32 ackermann( uint32 m, uint32 n )
{
if( m < 0 && n < 0 ) { exit(1); /* invalid m and n */ }
if( m == 0 ){ return n + 1; }
if( m > 0 && n == 0 ){ return ackermann( m - 1, 1 ); }
if( m > 0 && n > 0 ){ return ackermann( m - 1, ackermann(m, n - 1) ); }
}
The multiple comparisons of m > 0 are redundant (and can be simplified). Leaving them as-is, however, shows the standard definition of the Ackermann function.
But one does not have to go so far off the mathematical edge to find interesting recursive functions other than the Fibonnaci numbers.
You have the greatest common denominator (GDC) function, quicksort and the always typical binary search algorithm.
Anything which has a hierarchy.
For example listing all the employees beneath your boss.
Recursion finds its fundations in mathematical induction, and should be taught as such.
Defining functions by induction can be exposed clearly with list processing. There are many things to say about fold for instance.
Then, move on to trees.
It's not C++, obviously, but the concept is sound:
PHP recursively traversing nested multidimensional arrays:
public function recurse_me($collection) {
foreach ($collection as $value) {
if (is_array($value)) {
$this->recurse_me($value);
} else {
// process value.
}
}
}
I remember that I understood recursion by writing a programm, that searches for word ladders. In a given dictionary.
The academic example is the factorial
n!
calculum.
In real life, you get math libs.
There are sorting algorithms that rely on recursion.
And then, there's the binary search that is implemented with recursion.
Pascal's triangle
Heap sort is also a good example. You can read about it in "Introduction to Algorithms" by Cormen, Rivest and others. Great book, I hope you'll find a lot of interesting there.
Lots of operations on linked-node type structures can be recursive. Others have mentioned BSTs, but if you don't want to have to explain what those are, consider searching for the highest value in a linear, unsorted list:
int MaxValue(Node node)
{
if (node == null)
return 0;
if (node.Next == null)
return node.Value;
int maxNext = MaxValue(node.Next);
return node.Value > maxNext ? node.Value : maxNext;
}
Lists (in this case, linked lists) are very easy to explain in real-world terms; your audience doesn't even have to have a programming background. You can simply describe it as a group of unsorted boxes, or a list of numbers.