13.11.2014 Views

Introduction to Computational Linguistics

Introduction to Computational Linguistics

Introduction to Computational Linguistics

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

14. Digression: Time Complexity 53<br />

we let S i+1 be the set of successors of S i which are not in R i := R i−1 ∪ S i . The<br />

advantage of this algorithm is that it does not recompute the successors of a given<br />

point over and over. Instead, only the successors of point that have recently been<br />

added are calculated. It is easily seen that this algorithm computes the successors<br />

of a point only once. Thus, this algorithm is not even quadratic but linear in |Q|!<br />

And if the algorithm is linear — that is much better. Actually, you cannot get less<br />

than that if the entire input matters. For the machine needs <strong>to</strong> take a look at the<br />

input — and this take slinear time at least.<br />

It is not always the case that algorithms can be made as fast as this one. The<br />

problem of satisfiability of a given propositional formula is believed <strong>to</strong> take exponential<br />

time. More exactly, it is in NP — though it may take polynomial time in<br />

many cases. Regardless whether an algorithm takes a lot of time or not it is wise<br />

<strong>to</strong> try an reduce the number of steps that it actually takes. This can make a big<br />

difference when the application has <strong>to</strong> run on real life examples. Often, the best<br />

algorithms are not so difficult <strong>to</strong> understand — one just has <strong>to</strong> find them. Here<br />

is another one. Suppose you are given a list of numbers. Your task is <strong>to</strong> sort the<br />

list in ascending order as fast as possible. Here is the algorithm that one would<br />

normally use: scan the list for the least number and put it at the beginning of a new<br />

list; then scan the remainder for the least number and put that behind the number<br />

you already have, and so on. In step n you have you original list L, reduced by<br />

n − 1 elements, and a list L ′ containing n − 1 elements. To find the minimal element<br />

in L you do the following: you need two memory cells, C and P. C initially<br />

contains the first element of the list and P := 1. Now take the second element<br />

and see whether it is smaller than the content of C; if so, you put it in<strong>to</strong> C, and<br />

let P be the number of the cell; if not, you leave C and P as is. You need <strong>to</strong> do<br />

|L| − 1 comparisons, as you have <strong>to</strong> go through the entire list. When you are done,<br />

P tells you which element <strong>to</strong> put in<strong>to</strong> M. Now you start again. The number of<br />

comparisons is overall<br />

(136) (|L| − 1) + (|L| − 2) + . . . + 2 + 1 = |L| · (|L| − 1)/2<br />

This number grows quadratically. Not bad, but typically lists are very long, so we<br />

should try the best we can.<br />

Here is another algorithm. Divide the list in<strong>to</strong> blocks of two. (There might be<br />

a remainder of one element, but that does no harm.) We order these blocks. This<br />

takes just one comparison between the two elements of the block. In the next step<br />

we merge two blocks of two in<strong>to</strong> one block of four. In the third step we merge

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!