You can make a priority queue act like a normal queue by decreasing the priority of elements as you add them to the prority queue (that is, each new element has lower priority than all previously added elements). A variable can be used to keep track of the lowest priority used so far.

You can make a priority queue act like a stack by increasing the priority of elements as you add them to the priority queue.

100 / 22 / \ 11 30 / \ / 5 15 25 \ 9 / \ 7 10

15 / \ 10 25 / \ / \ 7 11 22 100 / \ / 5 9 30

Here are the hash codes

- adrian: 41 (mod 10 is 1)
- andrew: 59 (mod 10 is 9)
- jared: 33 (mod 10 is 3)
- sarah: 42 (mod 10 is 2)
- scott: 72 (mod 10 is 2)
- tomonori: 111 (mod 10 is 1)
- yuriy: 93 (mod 10 is 3)

If we chain, we get

- 0:
- 1: adrian, tomonori
- 2: sarah, scott
- 3: jared, yuriy
- 4:
- 5:
- 6:
- 7:
- 8:
- 9: andrew

If we rehash by offsetting by one we get

- adrian goes in position 1
- andrew goes in position 9
- jared goes in position 3
- sarah goes in position 2
- scott tries to go in position 2, tries to go in position 3, finally fits in position 4
- tonomori tries to go in positions 1, 2, 3, and 4 and finally fits in position 5
- yuriy tries to go in positions 3, 4, and 5, and finally fits in position 6.

If we rehash by increasing the table size by 1

- After inserting the first four elements,
- adrian is in position 1
- andrew is in position 9
- jared is in position 3
- sarah is in position 2

- When we try to insert scott we cause a collision and increase the size
of the table to 11. We then need to rehash
- adrian is in position 8
- andrew is in position 4
- jared is in position 0
- sarah is in position 2

- The remaining elements actually it in acceptablly well
- scott goes in position 6
- tomonori goes in position 1
- yuriy in position 5

- Depth 0: 1 node
- Root

- Depth 1: 2 nodes
- Root
- One child

- Depth 2: 4 nodes
- Root
- One almost-balanced subtree of depth 1 and size 2
- One almost-blanced subtree of depth 0 and size 1

- Depth 3: 7 nodes
- Root
- One almost-balanced subtree of depth 2 and size 4
- One almost-blanced subtree of depth 1 and size 2

- Depth 4: 12 nodes
- Root
- One almost-balanced subtree of depth 3 and size 7
- One almost-blanced subtree of depth 2 and size 4

- Depth 5: 20 nodes
- Root
- One almost-balanced subtree of depth 4 and size 12
- One almost-blanced subtree of depth 3 and size 7

- Depth 6: 33 nodes
- Root
- One almost-balanced subtree of depth 5 and size 20
- One almost-blanced subtree of depth 4 and size 12

- Depth 7: 54 nodes
- Root
- One almost-balanced subtree of depth 6 and size 33
- One almost-blanced subtree of depth 5 and size 20

- Depth 8: 88 nodes
- Root
- One almost-balanced subtree of depth 7 and size 54
- One almost-blanced subtree of depth 6 and size 33

- I call B (we'll assume that's free since it's not specified)
- B calls A (2), G (3), H (2)
- H calls C (1)
- A calls D (1), E (1), F (1), I (2)

The total cost of this tree is 13.

This is closely related to the minimum spanning tree algorithm, although
the MST algorithms we wrote were for *undirected* graphs. It turns
out that the policy of "pick a node to start with" doesn't work for
directed graphs, as you might tell by considering a two-node graph in
which it's cheap to go from A to B but expensive to go from B to A.

If you limit each person to one call, this is a close variant of the traveling salesperson problem.

/** * Compute a calling tree based on an n-by-n matrix. Assumes that * it is "free" to call the first person. Returns a dictionary that * specifies who each person calls. * pre: The matrix contains nonnegative nonnull entries. * post: A minimum caling tree is returned. * post: The underlying matrix isn't affected. */ public Dictionary callTree(Matrix m) { Iterator names = m.labels(); // The people Dictionary calls = new Dictionary(); // The thing we'll return Iterator callers = m.labels(); // Potential makers of calls Iterator callees = m.labels(); // Potential recipients of calls Iterator person; // One person in some list Iterator caller; // One person making a call Iterator callee; // One person receiving a call // Note: since we've assumed that the first call is free, we want // to make that the call to the person who would otherwise cost // more to call. Iterator max_call_cost = NOCALL; // The maximum cost of a call // found so far. Object max_caller; // The caller for that call Object max_callee; // The callee for that call // Initialize the dictionary so that each person has an empty // list of callees. for(names.reset(); names.hasMoreElements; ) { person = names.nextElement(); calls.add(person, new Linear()); } // for // For each person, determine how much it costs to call that person for(callees.reset(); callees.hasMoreElements; ) { callee = callees.nextElement(); // Get one caller callers.reset(); caller = callers.nextElement(); // Compare to others for(callers.reset(); callers.hasMoreElements; ) { person = callers.nextElement(); if (m.cost(person,callee) < m.cost(caller,callee)) { caller = person; } // if } // for // If it's cheaper to call that person than the most expensive // we've seen so far, add it. if (m.cost(caller,callee) <= max_call_cost) { calls.get(caller).add(callee); } // if cheap call // Otherwise, make the current one the most expensive and add // the previous most expensive. else { if (max_call_cost != NONCALL) { calls.get(max_caller).add(max_callee); } max_call_cost = m.cost(caller,callee); max_caller = caller; max_callee = callee; } // New most expensive call } // for each callee // We seem to be done return calls; } // callTree

This is an O(n^2) algorithm, assuming that we can get, reset, and traverse the list of nodes in O(n) time.

**Disclaimer** Often, these pages were created "on the fly" with little, if any, proofreading. Any or all of the information on the pages may be incorrect. Please contact me if you notice errors.

Source text last modified Tue Dec 16 17:34:35 1997.

This page generated on Wed Dec 17 08:32:44 1997 by SiteWeaver.

Contact our webmaster at rebelsky@math.grin.edu