Monday, September 22, 2014

linked list



Linked Lists
A linked list is a data structure that uses a "chain" of node objects, connected by pointers,
Minimal Linked List Interface
A linked list implementation will typically provide at least:
-        initialization function to set up basic structure for an empty list
-        insert functions to add new element to the list; at front, at rear, at user-selected position, ordered insertion
-        remove function to remove element from the list

-        find function to determine whether a given element occurs in the list
-        clear function to restore the list to an empty state
In C we would organize this as a pair of struct types (list and node) and a collection of associated functions.
Generic Node and List
#ifndef DLIST_H
#define DLIST_H
// List node: struct _DNode {
struct _DNode *prev;     // Previous list element struct _DNode *next;     // Next list element
} ;
// List object: struct _DList {
struct _DNode head;      // List head struct _DNode tail;      // List tail
} ;
typedef struct _DNode DNode; typedef struct _DList DList;
#endif
DList Initialization

This eliminates special cases, because every data node will always be between two other nodes.
We could also make head.prev point to tail and tail.next point to head, which would eliminate NULL pointers and allow the list to be used in a circular fashion.
Wrapping the Node in the Payload
We may use a single DList of DNode objects with any user data type, without sacrificing type-checking.
We merely have to create a "duct tape" object to attach a data object to a node:
#ifndef INTEGERDT_H
#define INTEGERDT_H #include "DList.h"
struct _IntegerDT {    // "duct tape" attaches data object to DNode int payload; DNode node;
} ;
typedef struct _IntegerDT IntegerDT;
void IntegerDT_Init(IntegerDT* const pLE, const int* const I); #endif
Example of "duct-taped" List Structure
The DList only "knows about" two DNode objects.

Each DNode object only "knows about" one or two other DNode objects.
The DList and Dnode objects "know" nothing of IntegerDT objects.
Inserting a DNode
We want to insert the node on the bottom between the other two nodes:

elem->next = before;       // 2 before->prev->next = elem; // 3 before->prev =  elem;       //  4
Inserting a DNode
The DList only "knows about" two DNode objects.
/* Inserts elem as the predecessor of before, which may be either an interior element or a tail.
*/ void DList_Insert (DNode* const before, DNode* const elem) {
assert (is_interior (before) || is_tail ( before)); assert (elem !=  NULL);
elem->prev =  before->prev; elem->next = before; before->prev->next = elem; before->prev =  elem;
}
Searching
Clearly, we need to be able to search a list for a data value that matches some 

But we must follow the list pointers, which tie the DNode objects together…
… so how are we going to access the user data objects?
Accessing the "duct tape"
Suppose the IntegerDT object is laid out in memory as shown:
IntegerDT

We want a pointer q that points to the IntegerDT object that contains the Dnode that p points to.
Then it appears we can set the value for q by subtracting 4 from p
… but that logic depends on the specific memory layout shown above.
offsetof() to the Rescue!
The Standard Library includes a relevant C macro:
offsetof(type, member-designator)
expands to an integer constant expression that has type size_t, the value of which is the offset in bytes, to the structure member (designated by member-designator), from the beginning of its structure (designated by type).


/* Converts pointer to a DNode NODE into a pointer to the structure that DNode is embedded inside. 
Supply the name of the outer structure STRUCT and the member name MEMBER of the DNode.
*/
#define DList_Entry(NODE, STRUCT, MEMBER)     \
((STRUCT *) ((uint8_t *) (NODE) – \


offsetof ( STRUCT, MEMBER )))
Traversing the DList
void traverseList(DList* pL) { DNode* e = DList_Head(pL);
while ( (e = DList_Next(e)) != DList_End(pL)) {
// Get pointer to the "duct-tape" object from //    the pointer to the DList element:
IntegerDT *p = DList_Entry(e, IntegerDT, node);
// Get value of payload within "duct-tape" object: int userData =  p->payload;
// do stuff with current user data element }
}


Here are some ideas for DList interface functions:
// Set up an empty list: void DList_Init(DList* pList);
// Insert node elem in front of node before: void DList_Insert(DNode* pBefore, DNode* pElem);
// Remove node elem:
DNode* DList_Remove(DNode* pElem);
// Is list empty? bool DList_Empty(DList* pList);
// Restore list to empty state: void Dlist_Clear(Dlist* pList);
. . .
. . .
// Get pointer to first/last data node in list:
DNode* DList_Begin(DList* pList);
DNode* DList_End(DList* pList);
// Get pointer to successor/predecessor of node:
DNode* DList_Next(DNode* pElem);
DNode* DList_Prev(DNode* pElem);
// Get pointer to head/tail of list:
DNode* DList_Head(DList* pList);
DNode* DList_Tail(DList* pList);
. . .
. . .
// Insert elem at front/rear of list:
void DList_PushFront(DList* pList, DNode* pElem); void DList_PushBack(DList* pList, DNode* pElem);
// Remove elem from front/rear of list:
DNode* DList_PopFront(DList* pList);
DNode* DList_PopBack(DList* pList);

 









No comments:

Post a Comment