Last time, we looked at how you can swap two adjacent blocks of memory using only forward iterators and noted that we can try to use the same trick to develop a forward-only solution to the problem of swapping two non-adjacent blocks of memory.
Our original diagram looked like this, with a block of memory of the form A1, A2, B1, B2, C1, C2, D1, D2, D3, E1, and the goal of swapping the B’s and D’s, producing A1, A2, D1, D2, D3, C1, C2, B1, B2, E1.
| A1 | A2 | B1 | B2 | C1 | C2 | D1 | D2 | D3 | E1 |
|  |  | ⤩ |  | ||||||
| A1 | A2 | D1 | D2 | D3 | C1 | C2 | B1 | B2 | E1 |
The first thing we’ll do is get rid of the A’s and E’s, since they aren’t really participants at all.
| B1 | B2 | C1 | C2 | D1 | D2 | D3 | |
|  |  | ⤩ |  | ||||
| D1 | D2 | D3 | C1 | C2 | B1 | B2 | |
If either the B or D block is empty, then we are left with a rotation, and we already know how to do that using only forward iterators.
Otherwise, start with first pointing at the start of B and mid pointing at the start of D.
| B1 | B2 | B3 | C1 | C2 | D1 | D2 | |
| ↑ |  |  |  |  | ↑ |  | ↑ |
| first | mid | last | |||||
Walk forward from first and mid, swapping the initial elements from B and D, until you either run out of B elements or run out of D elements.
Again, there are three cases.
If the B block is bigger than the D block, then our first pass finishes with the first pointer somewhere in the middle of the B block and the mid pointer making it all the way to the last.
| D1 | D2 | B3 | C1 | C2 | B1 | B2 | |
|  |  | ↑ |  |  |  |  | ↑ |
| Â | Â | first | mid last |
||||
The entire D block is in its final position, and getting the B3 block to the end is a rotation of [first, last) that moves C1 to the front, and we can use the existing forward-only rotation algorithm to finish the job.
The second case is that the D block is bigger than the B block. In this case, we finish with the first pointer at the end of the original B block and the mid in the middle of the original D block.
| D1 | D2 | C1 | C2 | B1 | B2 | D3 | |
|  |  | ↑ |  |  |  | ↑ | ↑ |
| Â | Â | first | mid | last | |||
Again, we can finish the job with a forward-only rotation, this time rotating the [first, last) block to put mid at the front.
The final case is that there are exactly the same number of B’s and D’s: All of the D’s have moved to the front and all of the B’s have moved to the back.
| D1 | D2 | C1 | C2 | B1 | B2 |
In this case, we are finished.
This final case does not need to be treated as a special case. We can just treat it as either of the first two cases, and the right thing will happen since the final forward-only rotation will realize that there is nothing to rotate. In fact, the vacuous case at the start (where either there are no B’s or no D’s) does not need to be treated as a special case either.
This algorithm performs n swaps because we perform k swaps in the first phase, and the rotation in the second phase is known to perform n − k swaps. You can also calculate this directly by observing that every swap moves one element to its final position.
0 comments
Be the first to start the discussion.