Presentation is loading. Please wait.

Presentation is loading. Please wait.

Given a node v of a doubly linked list, we can easily insert a new node z immediately after v. Specifically, let w the be node following v. We execute.

Similar presentations


Presentation on theme: "Given a node v of a doubly linked list, we can easily insert a new node z immediately after v. Specifically, let w the be node following v. We execute."— Presentation transcript:

1 Given a node v of a doubly linked list, we can easily insert a new node z immediately after v. Specifically, let w the be node following v. We execute the following steps: 1. make z's prev link refer to v 2. make z's next link refer to w 3. make w's prev link refer to z 4. make v's next link refer to z 3. Insertion in the Middle of a Doubly Linked List v z W

2 4. Removing from the Middle of a Doubly Linked List To remove a node v in the middle of a doubly linked list. We access the nodes u and w on either side of v using v's getPrev and getNext. To remove node v, we simply have u and w point to each other instead of to v. We refer to this operation as the linking out of v. We also null out v's prev and next pointers so as not to retain old references into the list.

3 v UW

4 Implementation of a Doubly Linked List

5

6

7

8

9 Circularly Linked Lists and Linked-List Sorting Circularly linked list : the same as singly linked list, each node in a circularly linked list has a next pointer and a reference to an element. There is no head or tail in a circularly linked list. The last node's next points back to the first node. There is no first or last node. If we traverse the nodes of a circularly linked list from any node by following next pointers, we will cycle through the nodes. Even though a circularly linked list has no beginning or end, we nevertheless need some node to be marked as a special node, which we call the cursor.

10 Some simple update methods for a circularly linked list: add(v): Insert a new node v immediately after the cursor; if the list is empty, then v becomes the cursor and its next pointer points to itself. remove(): Remove and return the node v immediately after the cursor,if the list becomes empty, the cursor is set to null. advance(): Advance the cursor to the next node in the list.

11 Java implementation of a circularly linked list

12

13 Recursion A way to fulfill repetition which occurs when a function refer to itself in its own definition. Example : Factorial Function For example, 5! = 5·4·3·2·1 = 120. To make the connection with methods clearer, we use the notation factorial(n) to denote n!. The factorial function can be defined in a manner that suggests a recursive formulation. factorial(5) = 5 · (4 · 3 · 2 · 1) = 5 · factorial(4). Thus, we can define factorial(5) in terms of factorial(4). In general, for a positive integer n, we can define factorial(n) to be n·factorial(n − 1).

14 This leads to the following recursive definition. The definition contains base cases, which are defined nonrecursively in terms of fixed quantities It also contains one or more recursive cases, which are defined by appealing to the definition of the function being defined.

15 Sorting Link List We show in following code the insertion-sort algorithm for a doubly linked list.

16 Recursion Trace

17 1. Linear Recursion A method is defined so that it makes at most one recursive call each time it is invoked. This type of recursion is useful when we view an algorithmic problem in terms of a first or last element plus a remaining set that has the same structure as the original set. Example1 : Summing the Elements of an Array Recursively

18 Recursion trace for an execution of LinearSum(A,n) with input parameters A = {4,3,6,2,5} and n = 5.

19 Example2 : Reversing an Array by Recursion Note that, in this algorithm, we actually have two base cases, namely, when i = j and when i > j. If n is odd, we will eventually reach the i = j case, and if n is even, we will eventually reach the i > j case.

20 Converting recursive algorithm to non- recursive algorithm. Easily done to algorithms uses tail recursion Tail recursion : when the algorithms use a liner recursion and make a recursive call as its very last operation. When an algorithm uses tail recursion, we can convert the recursive algorithm into a non-recursive one, by iterating through the recursive calls rather than calling them explicitly.

21 2. Binary Recursion When an algorithm makes two recursive calls, we say that it uses binary recursion. These calls can, for example, be used to solve two similar halves of some problem. Example 1: Summing Array elements we can sum the elements in A by: (i) recursively summing the elements in the first half of A; (ii) recursively summing the elements in the second half of A; (iii) adding these two values together

22 Recursion trace for the execution of BinarySum(0,8). the value of parameter n is halved at each recursive call. Thus, the depth of the recursion, that is, the maximum number of method instances that are active at the same time, is 1 + log 2 n Algorithm BinarySum uses an amount of additional space roughly proportional to this value. The running time of Algorithm BinarySum is still roughly proportional to n, however, since each box is visited in constant time when stepping through our algorithm and there are 2n − 1 boxes.

23 Example 2: Computing Fibonacci Numbers via Binary Recursion Recall that the Fibonacci numbers are recursively defined as follows: F 0 = 0 F 1 = 1 F i = F i − 1 + F i − 2 for i > 1.

24 In spite of the Fibonacci definition looking like a binary recursion, using this technique is inefficient in this case. It takes an exponential number of calls to compute the kth Fibonacci number in this way. Specifically, let n k denote the number of calls performed in the execution of BinaryFib(k). Then, we have the following values for the n k 's: n 0 = 1 n 1 = 1 n 2 = n 1 + n 0 + 1 = 1 + 1 + 1 = 3 n 3 = n 2 + n 1 + 1 = 3 + 1 + 1 = 5 n 4 = n 3 + n 2 + 1 = 5 + 3 + 1 = 9 n 5 = n 4 + n 3 + 1 = 9 + 5 + 1 = 15 n 6 = n 5 + n 4 + 1 = 15 + 9 + 1 = 25 n 7 = n 6 + n 5 + 1 = 25 + 15 + 1 = 41 n 8 = n 7 + n 6 + 1 = 41 + 25 + 1 = 67. we see that the number of calls more than doubles for each two consecutive indices. Thus, n k > 2 k/2, which means that BinaryFib(k) makes a number of calls that are exponential in k. In other words, using binary recursion to compute Fibonacci numbers is very inefficient.

25 Computing the kth Fibonacci number using linear recursion. Computing the kth Fibonacci number via linear recursion requires k method calls

26 3. Multiple Recursion Multiple recursion : when a method may make multiple recursive calls with that number potentially being more than two. Example : summation puzzles ( self study)

27 Recursion trace for an execution of PuzzleSolve(3,S,U), where S is empty and U = {a, b, c}. This execution generates and tests all permutations of a, b, and c. We show the permutations generated directly below their respective boxes


Download ppt "Given a node v of a doubly linked list, we can easily insert a new node z immediately after v. Specifically, let w the be node following v. We execute."

Similar presentations


Ads by Google