For correct code, you need to maintain the data structure invariants with each operation. The way the original code is written, the invariants look like this:
- A1:
front
points to the first element, if it exists; NULL
otherwise
- A2:
rear
points to the last element, if it exists; NULL
otherwise
You're claiming that the invariants could alternatively be these:
- B1:
front
points to the first element, if it exists; NULL
otherwise
- B2:
rear
points to the last element, if it exists
Now these are similar, but not at all identical. The B invariants don't require any particular value of rear
when the list is empty. Now you can use the B invariants to implement the list, sure, since it admits discrimination between empty and non-empty states, and that's enough to provide correct implementations.
But that doesn't say anything about whether A or B is better in practice. If you use the B invariants, a function to peek at the last element cannot simply return the value of rear
, since its value can be anything if the queue is empty; you have to test the front
value first.
// for the A2 invariant
return rear ;
// for the B2 invariant
return ( front == NULL ) ? NULL : rear ;
This boils down to whether to want to test-and-assign when you dequeue or whether to want to test when you peek at the last element. This is an optimization question, not a correctness one. If you never need to peek at the last element, you can optimize for that.
All this said, this a prime case for the hazards of premature optimization. An extra pointer assignment to NULL
is almost never going to be a performance problem. What's much more likely to be a problem is introducing a defect during maintenance when someone relies on the A invariants when the existing code is using the B ones. The A invariants are cognitively simpler, because front
and rear
are set up analogously, with neither having special behavior. The B invariants might perform better, but at the cost of complexity. Either choice might be better depending on your circumstances.
The Moral Of This Story: Always document your invariants.