Ptr distance

ABOUT TWO YEARS AGO, I IMPLEMENTED AN IDEA (USE SINGLE POINTER FIELD GET A
DOUBLY LINKED LIST ) . The comments are not
totally correct :slight_smile:

In a list, there would be two implicit dummy node ( one at the front and one
at the end ). I put the copyright with
the hope that I can sue someone using this code :). Just kidding, if it is
of any use go for it. But make sure you understand ( there is no bumper to
bumper warrenty :).

The findings are : Memory usage efficiency is really good ( leaving it as an
exercise ) for doubly link grid datastructure it would be magnificant.
Hardly any noticable time differences when runing on 5K, 10K, … 30K nodes.

Enjoy !!!

-pro

/* Created by Anjuta version 0.1.7 */
/* This file will not be overwritten */
/* COPYRIGHT “PROGRAMMERS SOCIETY INC. - PROKASH SINHA " */
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <time.h>
// use a single ptr to traverse back and forth
// //////////////////////////////////////////////
// | 0 | | 1 | | 2 | | 3 | | 4 | | 5 |
// |-----| |-----| |-----| |-----| |-----| |-----|
// |(1^0)| |(2^0)| |(3^1)| |(4^2)| |(5^3)| |(4^0)|
//
// Numerator of a node is the element.
// (m^n) is the exclusive or of ptr to m, and ptr to n.
// pStart points to element 0, pEnd points to 5 in this example
//
//
// pStart = pEnd = NULL => list is empty
// pStart = pEnd <> NULL => list is singleton

typedef int T;

//
// dbly link represented by ptr distance
//
typedef struct listNode{
T elm;
struct listNode * ptrdiff;
};

typedef struct listNode *plistNode;

//
// conventional dbly link representaion
//
typedef struct dlistNode {
T elm;
struct dlistNode *next;
struct dlistNode *prev;
};

typedef struct dlistNode *pdlistNode;
//

//globls for ptrdiff ds
plistNode pStart, pEnd;

//glbls for conventional
pdlistNode pdHead, pdEnd;

// * for ptrdiff
plistNode NextNode( plistNode pNode, plistNode pPrevNode)
{

return ((plistNode) ((int) pNode->ptrdiff ^ ( int)pPrevNode) );
}
//conventional
pdlistNode dNextNode ( pdlistNode pdNode)
{

return (pdNode->next );
}

pdlistNode dPrevNode ( pdlistNode pdNode)
{

return (pdNode->prev );
}
// ptr.dist list delete
void delList ()
{
//
plistNode pPrev, pCurrent;
pPrev = NULL;
pCurrent = pStart;

while ( pCurrent ) {
pCurrent->ptrdiff = NextNode( pCurrent, pPrev);
if (pPrev)
free(pPrev);
if ( !pCurrent->ptrdiff ){
printf(” Final node being deleted in prt.dist. =%d\n", pCurrent->elm);
free(pCurrent);
pCurrent = NULL;
continue;
}
pPrev = pCurrent;
pCurrent = pCurrent->ptrdiff;
}
}
// conventional list delete
void ddelList()
{
pdlistNode pdCurrent, pdNext;
pdCurrent = pdHead;
while (pdCurrent) {
pdNext = dNextNode(pdCurrent);
free(pdCurrent);
pdCurrent = pdNext;
}
}

// for dist. ptr.
void insertAfter ( plistNode pNew, T theElm )
{
plistNode pPrev, pCurrent, pNext;
pPrev = NULL;
pCurrent = pStart;

while (pCurrent) {
pNext = NextNode(pCurrent, pPrev);
if (pCurrent->elm == theElm ) {
/*fw traversal is done */
//
if (pNext ) { // fix the existing next node
pNext->ptrdiff = (plistNode) ((int)pNext->ptrdiff ^ ( int) pCurrent ^
(int)pNew );
}
//fix the current node
pCurrent->ptrdiff = (plistNode) ((int)pNew ^ (int)pNext ^
(int)pCurrent->ptrdiff);
//fix the new node
pNew->ptrdiff = (plistNode) ( (int)pCurrent ^ (int)pNext );
break;
}
pPrev = pCurrent;
pCurrent = pNext;
}
}
// * for conventional insertAfter()
void dinsertAfter(pdlistNode pdNew, T theElm )
{
pdlistNode pdPrev, pdCurrent, pdNext;
pdCurrent= pdHead;

while (pdCurrent) {
pdNext = dNextNode(pdCurrent);
if (pdCurrent->elm == theElm ) {
if (pdNext ) {//fix the existing next node
pdNext->prev = pdNew;
}
//fix the current node
pdCurrent->next = pdNew;
//fix the new node
pdNew->next = pdNext;
pdNew->prev = pdCurrent;
break;
}
pdCurrent = pdNext;
}
}

// ptr. dist. struct. traversal
void traverse( plistNode pRoot )
{
//
plistNode pCurrent, pPrev, pNext;

pPrev = NULL;
pCurrent = pRoot;

while (pCurrent)
{
//printf(" -> %d\n", pCurrent->elm) ;
pNext = NextNode(pCurrent, pPrev );
pPrev = pCurrent;
pCurrent = pNext;

}
}
// conventional forward traversal
void dtraversefw( pdlistNode pdHead )
{
//
pdlistNode pCurrent;
pCurrent = pdHead;
while (pCurrent)
{

//printf(" -> %d\n", pCurrent->elm) ;
pCurrent = dNextNode(pCurrent);

}
}
// conventional backward traversal
void dtraversebw( pdlistNode pdHead )
{
//
pdlistNode pCurrent;
pCurrent = pdHead;
while (pCurrent)
{
//printf(" -> %d\n", pCurrent->elm) ;
pCurrent = dPrevNode(pCurrent);
}
}
//
// dist. ptr. insertion
void insert( T elm)
{
//
plistNode pnewNode = (plistNode)malloc(sizeof(struct listNode) );
if (! pnewNode) {
printf(" malloc failed in insert( T elm) \n");
return;
}
pnewNode->elm = elm;
pnewNode->ptrdiff = NULL;

//brand new
if ( !pStart ) {
pStart = pEnd = pnewNode;

}else {
insertAfter( pnewNode, pEnd->elm);
pEnd = pnewNode;
}
return ;

}
//conventional insert
void dinsert ( T elm)
{
pdlistNode pdnewNode = (pdlistNode)malloc(sizeof(struct dlistNode) );
if (! pdnewNode) return;
pdnewNode->elm = elm;
pdnewNode->next = pdnewNode->prev = NULL;

//brand new
if ( !pdHead ) {
pdHead = pdEnd = pdnewNode;
}else {
dinsertAfter(pdnewNode, pdEnd->elm );
pdEnd = pdnewNode;
}
return ;
}

#define NO_OF_ITEM_IN_LIST 30000
//#define EXERCISE_PTR_DIST 1

void doTimeStamp (char * strArg)
{
char *pcharTime ;
time_t c_time;

time(&c_time);
pcharTime = ctime(&c_time);
printf(“%s %s\n”,strArg, pcharTime);

}
// exercise the conventional struct
void exerciseDlist()
{
char *pcharTime ;
time_t c_time;
int i;

doTimeStamp("Before conventional insert() " );
for (i = 0; i < NO_OF_ITEM_IN_LIST; i++)
dinsert ( (T) i );
doTimeStamp("After conventional insert() " );

printf (“Total Memory taken by conventional structure = %d bytes.\n”,
NO_OF_ITEM_IN_LIST *sizeof(struct dlistNode) );

//forward
doTimeStamp("Before conventioal dtraversefw(pdHead ) " );
dtraversefw(pdHead );
doTimeStamp("After conventioal dtraversefw(pdHead ) " );

//backward
doTimeStamp("Before conventioal dtraversebw(pdEnd) " );
dtraversebw(pdEnd);
doTimeStamp("After conventioal dtraversebw(pdEnd) " );

//delete
doTimeStamp("Before conventioal ddelList () " );
ddelList ();
doTimeStamp("After conventioal ddelList () " );
}

void exerciseDistptrlist()
{
int i;

doTimeStamp(“Before insert(prt.dist.)”);
// exercise the ptr distance structure
for (i = 0; i < NO_OF_ITEM_IN_LIST ; i++)
insert ( (T) i );
doTimeStamp( “After insert(prt.dist.)” );

printf (“Total Memory taken by ptr distance structure = %d bytes.\n”,
NO_OF_ITEM_IN_LIST *sizeof(struct listNode) );

//forward traversal
doTimeStamp ("Before traverse(pStart) of (prt.dist.) ");
traverse(pStart);
doTimeStamp( "After traverse(pStart) of(prt.dist.) ");
//backward traversal
doTimeStamp("Before traverse(pEnd) of (prt.dist.) ");
traverse(pEnd);
doTimeStamp( "After traverse(pEnd) of (prt.dist.) ");

//delete the whole list
doTimeStamp( "Before delList () of (prt.dist.) ");
delList ();
doTimeStamp("After delList () of (prt.dist.) ");

}

int main()

{
//exerciseDlist();
#ifdef EXERCISE_PTR_DIST
exerciseDistptrlist();
#else
exerciseDlist();
#endif

printf(“Hello world\n”);
return (0);
}</time.h></stdlib.h></assert.h></stdio.h>

Clever.

Could be quite useful, as long as you only ever want to traverse from
the head or tail of the list. Traditionally, I only use doubly linked
lists when I want the ability to traverse directly from a node in either
direction. This could be solved by creating an iterator object to hold
the prev and current pointer, though. That could also help obviate the
problem that you have to iterate through (potentially) the entire list
in order to insert or delete an element.

Also, insertion can be ambiguous if there are duplicated elements. Not a
big problem, usually, but it might be better to have an overloaded
insertAfter take a pointer to the desired node rather than the element
(you’d still have to search, of course, unless you have the prev pointer
lying around too, hence my iterator comment).

Also, perhaps I’m reading this wrong, but it looks to me like the
documentation block at the top of your code is a bit ambiguous (as in,
it uses “0” to refer to both NULL and the address of the zeroth node.
Element 0.ptrdiff is just the pointer to element 1, right (i.e. 1^NULL,
as opposed to 1^&elem0)? And similarly for element 5? If so, you could
optimize your tail insertion so it doesn’t need to traverse the list.

Prokash Sinha wrote:

ABOUT TWO YEARS AGO, I IMPLEMENTED AN IDEA (USE SINGLE POINTER FIELD GET A
DOUBLY LINKED LIST ) . The comments are not
totally correct :slight_smile:

In a list, there would be two implicit dummy node ( one at the front and one
at the end ). I put the copyright with
the hope that I can sue someone using this code :). Just kidding, if it is
of any use go for it. But make sure you understand ( there is no bumper to
bumper warrenty :).

The findings are : Memory usage efficiency is really good ( leaving it as an
exercise ) for doubly link grid datastructure it would be magnificant.
Hardly any noticable time differences when runing on 5K, 10K, … 30K nodes.

Enjoy !!!

-pro

/* Created by Anjuta version 0.1.7 */
/* This file will not be overwritten */
/* COPYRIGHT “PROGRAMMERS SOCIETY INC. - PROKASH SINHA " */
#include <stdio.h>
> #include <assert.h>
> #include <stdlib.h>
> #include <time.h>
> // use a single ptr to traverse back and forth
> // //////////////////////////////////////////////
> // | 0 | | 1 | | 2 | | 3 | | 4 | | 5 |
> // |-----| |-----| |-----| |-----| |-----| |-----|
> // |(1^0)| |(2^0)| |(3^1)| |(4^2)| |(5^3)| |(4^0)|
> //
> // Numerator of a node is the element.
> // (m^n) is the exclusive or of ptr to m, and ptr to n.
> // pStart points to element 0, pEnd points to 5 in this example
> //
> //
> // pStart = pEnd = NULL => list is empty
> // pStart = pEnd <> NULL => list is singleton
>
>
> typedef int T;
>
> //
> // dbly link represented by ptr distance
> //
> typedef struct listNode{
> T elm;
> struct listNode * ptrdiff;
> };
>
> typedef struct listNode *plistNode;
>
> //
> // conventional dbly link representaion
> //
> typedef struct dlistNode {
> T elm;
> struct dlistNode *next;
> struct dlistNode *prev;
> };
>
> typedef struct dlistNode *pdlistNode;
> //
>
> //globls for ptrdiff ds
> plistNode pStart, pEnd;
>
> //glbls for conventional
> pdlistNode pdHead, pdEnd;
>
> // * for ptrdiff
> plistNode NextNode( plistNode pNode, plistNode pPrevNode)
> {
>
> return ((plistNode) ((int) pNode->ptrdiff ^ ( int)pPrevNode) );
> }
> //conventional
> pdlistNode dNextNode ( pdlistNode pdNode)
> {
>
> return (pdNode->next );
> }
>
> pdlistNode dPrevNode ( pdlistNode pdNode)
> {
>
> return (pdNode->prev );
> }
> // ptr.dist list delete
> void delList ()
> {
> //
> plistNode pPrev, pCurrent;
> pPrev = NULL;
> pCurrent = pStart;
>
> while ( pCurrent ) {
> pCurrent->ptrdiff = NextNode( pCurrent, pPrev);
> if (pPrev)
> free(pPrev);
> if ( !pCurrent->ptrdiff ){
> printf(” Final node being deleted in prt.dist. =%d\n", pCurrent->elm);
> free(pCurrent);
> pCurrent = NULL;
> continue;
> }
> pPrev = pCurrent;
> pCurrent = pCurrent->ptrdiff;
> }
> }
> // conventional list delete
> void ddelList()
> {
> pdlistNode pdCurrent, pdNext;
> pdCurrent = pdHead;
> while (pdCurrent) {
> pdNext = dNextNode(pdCurrent);
> free(pdCurrent);
> pdCurrent = pdNext;
> }
> }
>
> // for dist. ptr.
> void insertAfter ( plistNode pNew, T theElm )
> {
> plistNode pPrev, pCurrent, pNext;
> pPrev = NULL;
> pCurrent = pStart;
>
> while (pCurrent) {
> pNext = NextNode(pCurrent, pPrev);
> if (pCurrent->elm == theElm ) {
> /*fw traversal is done */
> //
> if (pNext ) { // fix the existing next node
> pNext->ptrdiff = (plistNode) ((int)pNext->ptrdiff ^ ( int) pCurrent ^
> (int)pNew );
> }
> //fix the current node
> pCurrent->ptrdiff = (plistNode) ((int)pNew ^ (int)pNext ^
> (int)pCurrent->ptrdiff);
> //fix the new node
> pNew->ptrdiff = (plistNode) ( (int)pCurrent ^ (int)pNext );
> break;
> }
> pPrev = pCurrent;
> pCurrent = pNext;
> }
> }
> // * for conventional insertAfter()
> void dinsertAfter(pdlistNode pdNew, T theElm )
> {
> pdlistNode pdPrev, pdCurrent, pdNext;
> pdCurrent= pdHead;
>
> while (pdCurrent) {
> pdNext = dNextNode(pdCurrent);
> if (pdCurrent->elm == theElm ) {
> if (pdNext ) {//fix the existing next node
> pdNext->prev = pdNew;
> }
> //fix the current node
> pdCurrent->next = pdNew;
> //fix the new node
> pdNew->next = pdNext;
> pdNew->prev = pdCurrent;
> break;
> }
> pdCurrent = pdNext;
> }
> }
>
> // ptr. dist. struct. traversal
> void traverse( plistNode pRoot )
> {
> //
> plistNode pCurrent, pPrev, pNext;
>
> pPrev = NULL;
> pCurrent = pRoot;
>
> while (pCurrent)
> {
> //printf(" -> %d\n", pCurrent->elm) ;
> pNext = NextNode(pCurrent, pPrev );
> pPrev = pCurrent;
> pCurrent = pNext;
>
> }
> }
> // conventional forward traversal
> void dtraversefw( pdlistNode pdHead )
> {
> //
> pdlistNode pCurrent;
> pCurrent = pdHead;
> while (pCurrent)
> {
>
> //printf(" -> %d\n", pCurrent->elm) ;
> pCurrent = dNextNode(pCurrent);
>
>
> }
> }
> // conventional backward traversal
> void dtraversebw( pdlistNode pdHead )
> {
> //
> pdlistNode pCurrent;
> pCurrent = pdHead;
> while (pCurrent)
> {
> //printf(" -> %d\n", pCurrent->elm) ;
> pCurrent = dPrevNode(pCurrent);
> }
> }
> //
> // dist. ptr. insertion
> void insert( T elm)
> {
> //
> plistNode pnewNode = (plistNode)malloc(sizeof(struct listNode) );
> if (! pnewNode) {
> printf(" malloc failed in insert( T elm) \n");
> return;
> }
> pnewNode->elm = elm;
> pnewNode->ptrdiff = NULL;
>
> //brand new
> if ( !pStart ) {
> pStart = pEnd = pnewNode;
>
> }else {
> insertAfter( pnewNode, pEnd->elm);
> pEnd = pnewNode;
> }
> return ;
>
> }
> //conventional insert
> void dinsert ( T elm)
> {
> pdlistNode pdnewNode = (pdlistNode)malloc(sizeof(struct dlistNode) );
> if (! pdnewNode) return;
> pdnewNode->elm = elm;
> pdnewNode->next = pdnewNode->prev = NULL;
>
> //brand new
> if ( !pdHead ) {
> pdHead = pdEnd = pdnewNode;
> }else {
> dinsertAfter(pdnewNode, pdEnd->elm );
> pdEnd = pdnewNode;
> }
> return ;
> }
>
> #define NO_OF_ITEM_IN_LIST 30000
> //#define EXERCISE_PTR_DIST 1
>
>
> void doTimeStamp (char * strArg)
> {
> char *pcharTime ;
> time_t c_time;
>
> time(&c_time);
> pcharTime = ctime(&c_time);
> printf(“%s %s\n”,strArg, pcharTime);
>
> }
> // exercise the conventional struct
> void exerciseDlist()
> {
> char *pcharTime ;
> time_t c_time;
> int i;
>
> doTimeStamp("Before conventional insert() " );
> for (i = 0; i < NO_OF_ITEM_IN_LIST; i++)
> dinsert ( (T) i );
> doTimeStamp("After conventional insert() " );
>
> printf (“Total Memory taken by conventional structure = %d bytes.\n”,
> NO_OF_ITEM_IN_LIST *sizeof(struct dlistNode) );
>
> //forward
> doTimeStamp("Before conventioal dtraversefw(pdHead ) " );
> dtraversefw(pdHead );
> doTimeStamp("After conventioal dtraversefw(pdHead ) " );
>
> //backward
> doTimeStamp("Before conventioal dtraversebw(pdEnd) " );
> dtraversebw(pdEnd);
> doTimeStamp("After conventioal dtraversebw(pdEnd) " );
>
>
> //delete
> doTimeStamp("Before conventioal ddelList () " );
> ddelList ();
> doTimeStamp("After conventioal ddelList () " );
> }
>
> void exerciseDistptrlist()
> {
> int i;
>
> doTimeStamp(“Before insert(prt.dist.)”);
> // exercise the ptr distance structure
> for (i = 0; i < NO_OF_ITEM_IN_LIST ; i++)
> insert ( (T) i );
> doTimeStamp( “After insert(prt.dist.)” );
>
> printf (“Total Memory taken by ptr distance structure = %d bytes.\n”,
> NO_OF_ITEM_IN_LIST *sizeof(struct listNode) );
>
> //forward traversal
> doTimeStamp ("Before traverse(pStart) of (prt.dist.) ");
> traverse(pStart);
> doTimeStamp( "After traverse(pStart) of(prt.dist.) ");
> //backward traversal
> doTimeStamp("Before traverse(pEnd) of (prt.dist.) ");
> traverse(pEnd);
> doTimeStamp( "After traverse(pEnd) of (prt.dist.) ");
>
> //delete the whole list
> doTimeStamp( "Before delList () of (prt.dist.) ");
> delList ();
> doTimeStamp("After delList () of (prt.dist.) ");
>
> }
>
> int main()
>
> {
> //exerciseDlist();
> #ifdef EXERCISE_PTR_DIST
> exerciseDistptrlist();
> #else
> exerciseDlist();
> #endif
>
> printf(“Hello world\n”);
> return (0);
> }
>
>
>

–
…/ray..

Please remove “.spamblock” from my email address if you need to contact
me outside the newsgroup.</time.h></stdlib.h></assert.h></stdio.h>

Ray,
As I warned, that the comments are not totally correct :). About 2 yrs ago, it was accepted by Linux Journal. Soon it would be released on a special edition for Embedded system. And you are absolutely right, I did not make it a clean/crispy
for the publication, it was good enough to implement the general logic first.

  1. List is often thought as multi-set, so duplication etc is a matter of choice.

  2. The other primitives for DoublyLink data structures can be implemented

  3. Circular nature needs to be verified.

  4. Make the element field as ptr to object

  5. Finally kernelize, so the beauty and the beast of conquerring concurrency appears…

-pro

I first saw this approach described by Lewis and Denenberg in “Data
Structures and Their Algorithms” (HarperCollins Publishers) copyright
1991. They don’t cite a reference. The book contains several other
surprising little gems. In the past I’ve recommended this book to
colleagues who think they’ve seen all there is to know about lists and
trees. :wink:

Chuck

----- Original Message -----
From: “Prokash Sinha”
To: “Windows System Software Devs Interest List”
Sent: Thursday, July 15, 2004 11:19 AM
Subject: [ntdev] Ptr distance

> ABOUT TWO YEARS AGO, I IMPLEMENTED AN IDEA (USE SINGLE POINTER FIELD
GET A
> DOUBLY LINKED LIST ) . The comments are not
> totally correct :slight_smile:
>
> In a list, there would be two implicit dummy node ( one at the front
and one
> at the end ). I put the copyright with
> the hope that I can sue someone using this code :). Just kidding, if
it is
> of any use go for it. But make sure you understand ( there is no
bumper to
> bumper warrenty :).
>
> The findings are : Memory usage efficiency is really good ( leaving it
as an
> exercise ) for doubly link grid datastructure it would be magnificant.
> Hardly any noticable time differences when runing on 5K, 10K, … 30K
nodes.
>
> Enjoy !!!
>
>
> -pro

Using xor to implement doubly-linked lists is real old, it was probably
already known back in the 60’s or 70’s. I don’t have the book in front of
me, but I bet that if you look it up you’ll find it in Knuth.

Alberto.

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com]On Behalf Of Chuck Batson
Sent: Wednesday, July 21, 2004 2:19 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] Ptr distance

I first saw this approach described by Lewis and Denenberg in “Data
Structures and Their Algorithms” (HarperCollins Publishers) copyright
1991. They don’t cite a reference. The book contains several other
surprising little gems. In the past I’ve recommended this book to
colleagues who think they’ve seen all there is to know about lists and
trees. :wink:

Chuck

----- Original Message -----
From: “Prokash Sinha”
To: “Windows System Software Devs Interest List”
Sent: Thursday, July 15, 2004 11:19 AM
Subject: [ntdev] Ptr distance

> ABOUT TWO YEARS AGO, I IMPLEMENTED AN IDEA (USE SINGLE POINTER FIELD
GET A
> DOUBLY LINKED LIST ) . The comments are not
> totally correct :slight_smile:
>
> In a list, there would be two implicit dummy node ( one at the front
and one
> at the end ). I put the copyright with
> the hope that I can sue someone using this code :). Just kidding, if
it is
> of any use go for it. But make sure you understand ( there is no
bumper to
> bumper warrenty :).
>
> The findings are : Memory usage efficiency is really good ( leaving it
as an
> exercise ) for doubly link grid datastructure it would be magnificant.
> Hardly any noticable time differences when runing on 5K, 10K, … 30K
nodes.
>
> Enjoy !!!
>
>
> -pro

—
Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: xxxxx@compuware.com
To unsubscribe send a blank email to xxxxx@lists.osr.com

The contents of this e-mail are intended for the named addressee only. It
contains information that may be confidential. Unless you are the named
addressee or an authorized designee, you may not copy or use it, or disclose
it to anyone else. If you received it in error please notify us immediately
and then destroy it.

The idea is not definitely new. I first came across couple yrs back in an article it briefly mentioned, but could not find any implementation, surely that I did not search exhaustively :-).

If it is in Knuth’s book then it must be an exercise, and surely I would look
at them soon ( by the wkend) …

Again on tty, so could not include Chuck and Alberto’s msg.

In any case if you guys (anyone ) happen to recall about an implementation please let me know…

-pro