Ever since I started with 8086 Assembly Language programming, I have been hammering my mind about these Segments and Segment registers. The problem I am facing is that I can
In this answer, I am only giving an explanation for real mode. In protected mode, segementation is a bit more complicated and as you're probably never going to write a segmented protected mode program, I'm not going to explain this.
Segments are very simple actually. The 8086 CPU has four segment registers named cs, ds, es, and ss. when you access memory, the CPU computes the physical address like this:
physical_address = segment * 16 + effective_address
where effective_address is the address indicated by the memory operand and segment is the content of the segment register for this memory access. By default, cs is used when the CPU fetches code, ss is used for stack pushes and pops as well as memory operands with bp as the base register, es is used for certain special instructions and ds is used everywhere else. The segment register can be overridden using a segment prefix.
What does that mean in practice? The 8086 has 16 bit registers, so using a register to store an address allows us to address up to 65536 bytes of RAM. The idea behind using segment registers is that we can store additional bits of the address in a segment, allowing the programmer to address a bit more than 220 = 1048576 bytes = 1 MiB of RAM. This RAM is sliced into 65536 overlapping segments of 65536 bytes each, where each segment is one value you can load into a segment register.
Each of these segments starts at an address that is a multiple of 16 as you can see in the address computation logic above. You can tile the entire 1 MiB physical address space with 16 non-overlapping segments (as you explained in your question) values 0x0000, 0x1000, ..., 0xf000 but you can use any segment selector you like as well.