Generating an optimal binary search tree (Cormen)

2024/10/9 22:03:34

I'm reading Cormen et al., Introduction to Algorithms (3rd ed.) (PDF), section 15.4 on optimal binary search trees, but am having some trouble implementing the pseudocode for the optimal_bst function in Python.

Here is the example I'm trying to apply the optimal BST to:

enter image description here

Let us define e[i,j] as the expected cost of searching an optimal binary search tree containing the keys labeled from i to j. Ultimately, we wish to compute e[1, n], where n is the number of keys (5 in this example). The final recursive formulation is:

enter image description here

which should be implemented by the following pseudocode:

enter image description here

Notice that the pseudocode interchangeably uses 1- and 0-based indexing, whereas Python uses only the latter. As a consequence I'm having trouble implementing the pseudocode. Here is what I have so far:

import numpy as npp = [0.15, 0.10, 0.05, 0.10, 0.20]
q = [0.05, 0.10, 0.05, 0.05, 0.05, 0.10]
n = len(p)e = np.diag(q)
w = np.diag(q)
root = np.zeros((n, n))
for l in range(1, n+1):for i in range(n-l+1):j = i + le[i, j] = np.infw[i, j] = w[i, j-1] + p[j-1] + q[j]for r in range(i, j+1):t = e[i-1, r-1] + e[r, j] + w[i-1, j]if t < e[i-1, j]:e[i-1, j] = troot[i-1, j] = rprint(w)
print(e)

However, if I run this the weights w get computed correctly, but the expected search values e remain 'stuck' at their initialized values:

[[ 0.05  0.3   0.45  0.55  0.7   1.  ][ 0.    0.1   0.25  0.35  0.5   0.8 ][ 0.    0.    0.05  0.15  0.3   0.6 ][ 0.    0.    0.    0.05  0.2   0.5 ][ 0.    0.    0.    0.    0.05  0.35][ 0.    0.    0.    0.    0.    0.1 ]]
[[ 0.05   inf   inf   inf   inf   inf][ 0.    0.1    inf   inf   inf   inf][ 0.    0.    0.05   inf   inf   inf][ 0.    0.    0.    0.05   inf   inf][ 0.    0.    0.    0.    0.05   inf][ 0.    0.    0.    0.    0.    0.1 ]]

What I expect is that e, w, and root be as follows:

enter image description here

I've been debugging this for a couple of hours by now and am still stuck. Can someone point out what is wrong with the Python code above?

Answer

It appears to me that you made a mistake in the indices. I couldn't make it work as expected but the following code should give you an indication where I was heading at (there is probably an off by one somewhere):

import numpy as npp = [0.15, 0.10, 0.05, 0.10, 0.20]
q = [0.05, 0.10, 0.05, 0.05, 0.05, 0.10]
n = len(p)def get2(m, i, j):return m[i - 1, j - 1]def set2(m, i, j, v):m[i - 1, j - 1] = vdef get1(m, i):return m[i - 1]def set1(m, i, v):m[i - 1] = ve = np.diag(q)
w = np.diag(q)
root = np.zeros((n, n))
for l in range(1, n + 1):for i in range(n - l + 2):j = i + l - 1set2(e, i, j, np.inf)set2(w, i, j, get2(w, i, j - 1) + get1(p, j) + get1(q, j))for r in range(i, j + 1):t = get2(e, i, r - 1) + get2(e, r + 1, j) + get2(w, i, j)if t < get2(e, i, j):set2(e, i, j, t)set2(root, i, j, r)print(w)
print(e)

The result:

[[ 0.2   0.4   0.5   0.65  0.9   0.  ][ 0.    0.2   0.3   0.45  0.7   0.  ][ 0.    0.    0.1   0.25  0.5   0.  ][ 0.    0.    0.    0.15  0.4   0.  ][ 0.    0.    0.    0.    0.25  0.  ][ 0.5   0.7   0.8   0.95  0.    0.3 ]]
[[ 0.2   0.6   0.8   1.2   1.95  0.  ][ 0.    0.2   0.4   0.8   1.35  0.  ][ 0.    0.    0.1   0.35  0.85  0.  ][ 0.    0.    0.    0.15  0.55  0.  ][ 0.    0.    0.    0.    0.25  0.  ][ 0.7   1.2   1.5   2.    0.    0.3 ]]
https://en.xdnf.cn/q/69905.html

Related Q&A

Pydub from_mp3 gives [Errno 2] No such file or directory

I find myself in front of a wall here, simply trying to load an audio file into pydub for converting it keeps on throwing a "[Errno 2] No such file or directory" error.Naturally I have spent …

Compile Python 3.6.2 on Debian Jessie segfaults on sharedmods

Im trying to compile Python 3.6.2 on a Debian Jessie box with the options./configure --prefix="/opt/python3" \ --enable-optimizations \--with-lto \ --enable-profiling \ --enable-unicode=ucs4 …

Escape space in filepath

Im trying to write a python tool that will read a logfile and process itOne thing it should do is use the paths listed in the logfile (its a logfile for a backup tool)/Volumes/Live_Jobs/Live_Jobs/*SCAN…

How to save web page as text file?

I would like to save a web page (all content) as a text file. (As if you did right click on webpage -> "Save Page As" -> "Save as text file" and not as html file)I have tried …

PIL Image.size returns the opposite width/height

Using PIL to determine width and height of imagesOn a specific image (luckily only this one - but it is troubling) the width/height returning from image.size is the opposite. The image: http://storage.…

Django Rest Framework: Register multiple serializers in ViewSet

Im trying to create a custom API (not using models), but its not showing the request definition in the schema (in consequence, not showing it in swagger). My current code is:views.pyclass InfoViewSet(v…

Which is most accurate way to distinguish one of 8 colors?

Imagine we how some basic colors:RED = Color ((196, 2, 51), "RED") ORANGE = Color ((255, 165, 0), "ORANGE") YELLOW = Color ((255, 205, 0), "YELLOW") GREEN = Color ((0, 128…

Lambda function behavior with and without keyword arguments

I am using lambda functions for GUI programming with tkinter. Recently I got stuck when implementing buttons that open files: self.file="" button = Button(conf_f, text="Tools opt.",…

How to get type annotation within python function scope?

For example: def test():a: intb: strprint(__annotations__) test()This function call raises a NameError: name __annotations__ is not defined error. What I want is to get the type annotation within the f…

General explanation of how epoll works?

Im doing a technical write-up on switching from a database-polling (via synchronous stored procedure call) to a message queue (via pub/sub). Id like to be able to explain how polling a database is vas…