很久没有来CSDN,也很久没有写东西了。去年12月在OSCHINA注册了号,发了两段code。这次转过来,以便日后查阅。
连接:http://www.oschina.net/code/snippet_737017_16964
这是一段静态链表的实现,其间用到了一种简单的内存管理策略——空闲链表。
这段代码里的“静态”是一个预先分配好的 node array,实际情况下可能会是一个一次性申请的较大的memory block。
其实是在这段 node array上维护两个链表,一个used list,一个free list,即代码中的idata,和ifree。
// 静态链表 的实现 #include <stdio.h> #define MAXN 16 // capacity of list. typedef int element; // element type. // define boolean type: typedef int bool; #define true -1 #define false 0 #define NPTR -1 // null pointer definition. can not between 0 to MAXN-1. typedef int pointer; #define DEBUGVAL(x) printf("%s: %d\n", #x, (x)); // a macro for debug. struct __node { element data; pointer next; }SLList[MAXN]; pointer ifree, idata; #define nextof(p) SLList[p].next #define dataof(p) SLList[p].data #define _alloc(d) ifree; dataof(ifree)=(d); ifree != NPTR ? ifree=nextof(ifree) : NPTR #define _free(p) nextof(p)=ifree; ifree = p void init() { int i; ifree = 0; idata = NPTR; for( i=0; i < MAXN-1; i++) nextof(i) = i+1; nextof(i) = NPTR; } // clear all nodes. void clear() { init(); } // push val to front. bool push_front(element val) { pointer tmp, np; if( ifree != NPTR ) { np = _alloc(val); nextof(np) = idata; idata = np; return true; } return false; } // push val to end of list. bool push_back(element val) { if( idata == NPTR ) { // 空表,直接写入 idata = _alloc(val); nextof(idata) = NPTR; return true; } if( ifree != NPTR ) { // 非空,先找到最后一个节点 pointer last = idata, np; while( nextof(last) != NPTR ) last = nextof(last); np = _alloc(val); nextof(np) = NPTR; nextof(last) = np; return true; } return false; } // insert val to after p pointed node. bool insert_after(pointer p, element val) { if( ifree != NPTR && p != NPTR ) { pointer pn = _alloc(val); nextof(pn) = nextof(p); nextof(p) = pn; return true; } return false; } // insert to the position in front of p. bool insert(pointer ptr, element val) { if( ifree == NPTR ) return false; // 没有结点,直接返回 if( ptr == idata ) { // 有一个节点 pointer np = _alloc(val); nextof(np) = idata; idata = np; return true; } else { // 其他情况,先找 ptr 的前驱,再插入 pointer p = idata; while( p != NPTR ) { if( nextof(p) == ptr ) { // find p -- the prev node of ptr. return insert_after(p, val); // insert val after p. } p = nextof(p); } } return false; } // find element, return the prev node pointer. pointer find_prev(element val) { pointer p = idata; while( p != NPTR ) { if( dataof( nextof(p) ) == val ) return p; p = nextof(p); } return NPTR; } // find element, return the node pointer. pointer find(element val) { pointer p = idata; while( p != NPTR ) { if( dataof(p) == val ) return p; p = nextof(p); } return NPTR; } // pop front element. void pop_front() { if( idata != NPTR ) { // 将 data list 最前面的节点 移到 free list 上 #if 0 pointer p = idata; idata = nextof(idata); // idata = nextof(idata); nextof(p) = ifree; // SLList[p].next = ifree; ifree = p; #else pointer p = idata; idata = nextof(idata); _free(p); #endif } } // pop back element. void pop_back() { if( idata == NPTR ) return; if( nextof(idata) == NPTR ) { // only 1 node. nextof(idata) = ifree; ifree = idata; idata = NPTR; } else { // 找到最后一个节点 p,以及它的前驱 q. // TODO: find the lase nod p, and it's perv node q. pointer p = idata, q; while( nextof(p) != NPTR ) { q = p; p = nextof( p ); } // remove *p to free list, update nextof(q) to NPTR. nextof(p) = ifree; ifree = p; nextof(q) = NPTR; } }
完整代码及测试见:http://www.oschina.net/code/snippet_737017_16964
记得曾经在反《算法导论》的时候好像看到书中提到静态链表的实现问题,当时没有在意,直到去年写下这段代码的时候任然没有详细去看;今天翻出电子版一看,有近两页篇幅描述。
《算法导论》中的描述还是较为精炼的,文字不多,条理清晰,这里有一副原书中的插图,书中先讲了在没有指针的语言中如何表示指针和对象;
然后,话锋一转,在这样的情况下“Thus, it is useful to manage the storage of objects not currently used in the linked-list representation so that one can be allocated.”
然后书中也给出了伪代码:(要是早知道,我也那个夜晚也不用搞到两点了☺)
ALLOCATE-OBJECT() if free = NIL then error "out of space" else x ← free free ← next[x] return x
FREE-OBJECT(x) 1 next[x] ← free 2 free ← x