Sei sulla pagina 1di 4

Advantages:

Linked lists are a dynamic data structure, allocating the needed memory when the
program is initiated.
Insertion and deletion node operations are easily implemented in a linked list.
Linear data structures such as stacks and queues are easily executed with a linked list.
They can reduce access time and may expand in real time without memory overhead.

Disadvantages:

They have a tendency to waste memory due to pointers requiring extra storage space.
Nodes in a linked list must be read in order from the beginning as linked lists are
inherently sequential access.
Nodes are stored incontiguously, greatly increasing the time required to access individual
elements within the list.

Difficulties arise in linked lists when it comes to reverse traversing. Singly linked lists are
extremely difficult to navigate backwards, and while doubly linked lists are somewhat
easier to read, memory is wasted in allocating space for a back pointer. Two cases: Base
Case and General Case

There are four important criteria to think about when writing a recursive function.

1. What is the base case, and can it be solved?


2. What is the general case?
3. Does the recursive call make the problem smaller and approach the base case?

Base Case

The base case, or halting case, of a function is the problem that we know the answer to, that can
be solved without any more recursive calls. The base case is what stops the recursion from
continuing on forever. Every recursive function must have at least one base case (many functions
have more than one). If it doesn't, your function will not work correctly most of the time, and
will most likely cause your program to crash in many situations, definitely not a desired effect.

Let's return to our factorial example from above. Remember the problem was that we never
stopped the recursion process; we didn't have a base case. Luckily, the factorial function in math
defines a base case for us. n! = n*(n - 1)! as long as n > 1 . If n = = 1 or n = = 0 , then n! = 1 .
The factorial function is undefined for values less than 0, so in our implementation, we'll return
some error value. Using this updated definition, let's rewrite our factorial function.

int factorial(int n)
{
if (n<0) return 0; /* error value for inappropriate input
*/
else if (n<=1) return 1; /* if n==1 or n==0, n! = 1 */
else return n * factorial(n-1); /* n! = n * (n-1)! */
}

That's it! See how simple that was? Lets visualize what would happen if we were to invoke this
function, for example factorial(3):

Figure %: 3! = 3*2! = 3*2*1

The General Case

The general case is what happens most of the time, and is where the recursive call takes place. In
the case of factorial, the general case occurs when n > 1 , meaning we use the equation and
recursive definition n! = n*(n - 1)! .

Diminishing Size of Problem

Our third requirement for a recursive function is that the on each recursive call the problem must
be approaching the base case. If the problem isn't approaching the base case, we'll never reach it
and the recursion will never end. Imagine the following incorrect implementation of factorial:

/* this is incorrect */
int factorial(int n)
{
if (n<0) return 0;
else if (n<=1) return 1;
else return n * factorial(n+1);
}

Note that on each recursive call, the size of n gets bigger, not smaller. Since we initially start out
larger than our base cases (n==1 & n==0), we will be going away from the base cases, not
towards them. Thus we will never reach them. Besides being an incorrect implementation of the
factorial algorithm, this is bad recursive design. The recursively called problems should always
be heading towards the base case.

Avoiding Circularity
Another problem to avoid when writing recursive functions is circularity. Circularity occurs
when you reach a point in your recursion where the arguments to the function are the same as
with a previous function call in the stack. If this happens you will never reach your base case,
and the recursion will continue forever, or until your computer crashes, whichever comes first.

For example, let's say we had the function:

void not_smart(int value)


{
if (value == 1) return not_smart(2);
else if (value == 2) return not_smart(1);
else return 0;
}

If this function is called with the value 1, then it calls itself with the value 2, which in turn calls
itself with the value 1. See the circularity?

Sometimes it is hard to determine if a function is circular. Take the Syracuse problem for
example, which dates back to the 1930s.

int syracuse(int n)
{
if (n==1) return 0;
else if (n % 2 != 0) return syracuse(n/2);
else return 1 + syracuse(3*n + 1);
}

For small values of n , we know that this function is not circular, but we don't know if there is
some special value of n out there that causes this function to become circular.

Efficiency

Recursion might not be the most efficient way to implement an algorithm. Each time a function
is called, there is a certain amount of "overhead" that takes up memory and system resources.
When a function is called from another function, all the information about the first function must
be stored so that the computer can return to it after executing the new function.

The Call Stack

When a function is called, a certain amount of memory is set aside for that function to use for
purposes such as storing local variables. This memory, called a frame, is also used by the
computer to store information about the function such as the function's address in memory; this
allows the program to return to the proper place after a function call (for example, if you write a
function that calls printf(), you would like control to return to your function after printf()
completes; this is made possible by the frame).
Every function has its own frame that is created when the function is called. Since functions can
call other functions, often more than one function is in existence at any given time, and therefore
there are multiple frames to keep track of. These frames are stored on the call stack, an area of
memory devoted to holding information about currently running functions.

Potrebbero piacerti anche