To be truly inexpensive, you have to have the pointer to the place you
already want to insert it at, but the process goes like this:
Object is comprised of pointers:
[<--prev]
[next-->]
You have the original object:
obj.prev
obj.next
This involves three logical items in the linked list, but only two
of them will be in play depending on whether or not you are inserting
before or after:
left // Before only
target // Before and after
right // After only
And when you want to insert something in the middle, it involves
a fourth item, which is always in play:
new
So, to complete an operation of adding into a linked list, you
perform these steps, assuming you want to insert before the
target:
(1) Create new, and connect (operations broken out here):
(2) left->next = new
(3) new->prev = left
(4) new->next = target
(5) target->prev = new
And if inserting after:
(1) Create new, and connect (operations broken out here):
(2) right->prev = new
(3) new->next = right
(4) new->prev = target
(5) target->next = new
No matter where you insert in the middle, those are your operations.
If you insert at the end or at the beginning, you may also need to
update parent information about the first and last members, otherwise
the operation is the same except you don't hook up things which point
to NULL. You can either do that as an explicit alternate step for
beg/end operations, or you can just check for NULL pointers on left
and right operations on each add and use a single algorithm.
There is some machine expense in this operation because you don't
know where in memory these items will be added. But that is also
negated by using a builder to pre-allocate a block of memory to
contain large groups of link-list objects so when you traverse they
are in large chunks sequentially in memory. In such a case you can
also then create a reuse link list as well, which are a list of now
retired former items which can be recycled without explicit new and
delete operations, but only obj->isActive = true; and
obj->isActive = false; operations.