• No se han encontrado resultados

Cuadro comparativo de facilidad de hacer negocios

In document Guía de Implantación Ecua E dor2021 (página 15-33)

2

C h a p t e r

C h a p t e r O b j e c t i v e s

To understand the meaning of big‐O notation and how it is used as a measure of an algorithm’s efficiency

To become familiar with the List interface and the Java Collections Framework

To understand how to write an array‐based implementation of the List interface

To study the differences between single‐, double‐, and circular‐linked list data structures

To learn how to implement a single‐linked list

To learn how to implement the List interface using a double‐linked list

To understand the Iterator interface

To learn how to implement the Iterator for a linked list

To become familiar with the Java Collections Framework

First, we will discuss algorithm efficiency and how to characterize the efficiency of an algorithm. You will learn about big‐O notation, which you can use to compare the relative efficiency of different algorithms.

L i s t s a n d t h e C o l l e c t i o n s F r a m e w o r k

2.1 Algorithm Efficiency and Big‐O

2.2 The List Interface and ArrayList Class 2.3 Applications of ArrayList

2.4 Implementation of an ArrayList Class 2.5 Single‐Linked Lists

2.6 Double‐Linked Lists and Circular Lists

2.7 The LinkedList Class and the Iterator,ListIterator, and Iterable Interfaces 2.8 Application of the LinkedList Class

Case Study: Maintaining an Ordered List 2.9 Implementation of a Double‐Linked List Class 2.10 The Collections Framework Design

2.1 Algorithm Efficiency and Big-O

Whenever we write a new class, we will discuss the efficiency of its methods so that you know how they compare to similar methods in other classes. You can’t easily measure the amount of time it takes to run a program with modern computers. When you issue the command

java MyProgram

(or click the Run button of your integrated development environment [IDE]), the operating system first loads the Java Virtual Machine (JVM). The JVM then loads the .class file for MyProgram, it then loads other .class files that MyProgram references, and finally your pro-gram executes. (If the .class files have not yet been created, the Java IDE will compile the source file before executing the program.) Most of the time it takes to run your program is occupied with the first two steps. If you run your program a second time immediately after the first, it may seem to take less time. This is because the operating system may have kept the files in a local memory area called a cache. However, if you have a large enough or com-plicated enough problem, then the actual running time of your program will dominate the time required to load the JVM and .class files.

Because it is very difficult to get a precise measure of the performance of an algorithm or pro-gram, we normally try to approximate the effect of a change in the number of data items, n, that an algorithm processes. In this way, we can see how an algorithm’s execution time increases with respect to n, so we can compare two algorithms by examining their growth rates.

For many problems, there are algorithms that are relatively obvious but inefficient. Although every day computers are getting faster, with larger memories, there are algorithms whose growth rate is so large that no computer, no matter how fast or with how much memory, can solve the problem above a certain size. Furthermore, if a problem that has been too large to be solved can now be solved with the latest, biggest, and fastest supercomputer, adding a few more inputs may make the problem impractical, if not impossible, again. Therefore, it is important to have some idea of the relative efficiency of different algorithms. Next, we see how we might obtain such an idea by examining three methods in the following examples.

2.1 Algorithm Efficiency and Big-O 55

E X A M P L E 2 . 1 Consider the following method, which searches an array for a value:

public static int search(int[] x, int target) { for (int i = 0; i < x.length; i++) {

if (x[i] == target) return i;

}

// target not found return ‐1;

}

If the target is not present in the array, then the for loop body will be executed x.length

times. If the target is present, it could be anywhere. If we consider the average over all cases where the target is present, then the loop body will execute x.length/2 times. Therefore, the total execution time is directly proportional to x.length. If we doubled the size of the array, we would expect the time to double (not counting the overhead discussed earlier).

E X A M P L E 2 . 2 Now let us consider another problem. We want to find out whether two arrays have no common elements. We can use our search method to search one array for values that are in the other.

/** Determine whether two arrays have no common elements.

@param x One array @param y The other array

@return true if there are no common elements

*/

public static boolean areDifferent(int[] x, int[] y) { for (int i = 0; i < x.length; i++) {

if (search(y, x[i]) != ‐1) return false;

}

return true;

}

The loop body will execute at most x.length times. During each iteration, it will call method

search to search for current element, x[i], in array y. The loop body in search will execute at most y.length times. Therefore, the total execution time would be proportional to the product of x.length and y.length.

E X A M P L E 2 . 3 Let us consider the problem of determining whether each item in an array is unique. We could write the following method:

/** Determine whether the contents of an array are all unique.

@param x The array

@return true if all elements of x are unique

*/

public static boolean areUnique(int[] x) { for (int i = 0; i < x.length; i++) { for (int j = 0; j < x.length; j++) { if (i != j && x[i] == x[j]) return false;

} }

return true;

}

If all values are unique, the outer loop will execute x.length times. For each iteration of the outer loop, the inner loop will also execute x.length times. Thus, the total number of times the body of the inner loop will execute is (x.length)2.

E X A M P L E 2 . 4 The method we showed in Example 2.3 is very inefficient because we do approximately twice as many tests as necessary. We can rewrite the inner loop as follows:

/** Determine whether the contents of an array are all unique.

@param x The array

@return true if all elements of x are unique

*/

public static boolean areUnique(int[] x) { for (int i = 0; i < x.length; i++) {

for (int j = i + 1; j < x.length; j++) { if (x[i] == x[j])

return false;

} }

return true;

}

We can start the inner loop index at i + 1 because we have already determined that elements preceding this one are unique. The first time, the inner loop will execute x.length−1 times.

The second time, it will execute x.length–2 times, and so on. The last time, it will execute just once. The total number of times it will execute is

x.length-1 + x.length-2 +. . .+ 2 + 1

The series 1 2 3 · · · (n–1) is a well‐known series that has a value of

n (n ) n n

1 or

2 2

2

Therefore, this sum is

x.length2 x.length 2

In document Guía de Implantación Ecua E dor2021 (página 15-33)

Documento similar