Although many programmers grumbled about the 8086 segmented architecture when it came out, and although a few things could have been done to improve it (but weren't), it's nonetheless better at providing a meg of fungible memory address space than any other 16-bit architecture I know of.
Each logical address consists of two parts: a 16-bit segment and a 16-bit offset. Physical addresses are generated by adding the segment register, shifted left four bits, to the offset register (not shifted) and outputting the 20-bit result. Thus, segment 0000 [all numbers in hex] offsets 0000 to FFFF represent physical addresses 00000 to 0FFFF. Adding those offsets to various other segments will yield other address ranges:
Seg. Phys. Range
FFFF FFFF0-0FFEF (or 10FFEF if higher physical addressing bits exist)
One useful effect of this is that if memory can be divided into logical chunks of 64K or less each, aligned on 16-byte boundaries, one can determine for each chunk (at the time of allocation, which could be when code is linked, when it's loaded, or while it's executing) the segment value where the chuck should. One can then access memory within any chunk by simply loading that pre-determined segment value and then using offsets directly, without having to do any actual computation on segment registers. Because the segment register is multiplied by 16 when computing a physical address, chunks have to be aligned on 16-byte boundaries. In exchange for that minor inconvenience, however, one gains the ability to have memory chunks cross 64K boundaries without restriction or hassle.