分享一段代码,一个静态链表的C语言实现,其中包含着一种简单的内存管理策略:固定大小的链式管理。
在动手之前我一直以为静态链表和动态链表没有什么差别,细细一想才发现,原来静态链表之中隐藏着一个非常值得讨论的话题——内存管理。
静态链表的“静态”二字是指内存的来源为静态内存(通常用全局数组)。与动态链表不同,在静态链表中节点内存的申请与释放都需要自行维护,由于这里是链表,也很容易想到将空余的节点链接起来形成一个free_list,每次需要时从free_list头部取出一个节点,释放时再将节点加到头部,这样就能够非常容易的实现链表的其他操作。
1 // 静态链表 的实现 2 #include <stdio.h> 3 4 #define MAXN 16 // capacity of list. 5 typedef int element; // element type. 6 7 // define boolean type: 8 typedef int bool; 9 #define true -1 10 #define false 0 11 12 #define NPTR -1 // null pointer definition. can not between 0 to MAXN-1. 13 typedef int pointer; 14 15 #define DEBUGVAL(x) printf("%s: %d\n", #x, (x)); // a macro for debug. 16 17 struct __node 18 { 19 element data; 20 pointer next; 21 }SLList[MAXN]; 22 pointer ifree, idata; 23 24 #define nextof(p) SLList[p].next 25 #define dataof(p) SLList[p].data 26 27 #define _alloc(d) ifree; dataof(ifree)=(d); ifree != NPTR ? ifree=nextof(ifree) : NPTR 28 #define _free(p) nextof(p)=ifree; ifree = p 29 30 void init() 31 { 32 int i; 33 ifree = 0; 34 idata = NPTR; 35 for( i=0; i < MAXN-1; i++) 36 nextof(i) = i+1; 37 nextof(i) = NPTR; 38 } 39 40 // clear all nodes. 41 void clear() { init(); } 42 43 // push val to front. 44 bool push_front(element val) 45 { 46 pointer tmp, np; 47 if( ifree != NPTR ) { 48 np = _alloc(val); 49 nextof(np) = idata; 50 idata = np; 51 return true; 52 } 53 return false; 54 } 55 56 // push val to end of list. 57 bool push_back(element val) 58 { 59 if( idata == NPTR ) { // 空表,直接写入 60 idata = _alloc(val); 61 nextof(idata) = NPTR; 62 return true; 63 } 64 if( ifree != NPTR ) { // 非空,先找到最后一个节点 65 pointer last = idata, np; 66 while( nextof(last) != NPTR ) last = nextof(last); 67 np = _alloc(val); 68 nextof(np) = NPTR; 69 nextof(last) = np; 70 return true; 71 } 72 return false; 73 } 74 75 // insert val to after p pointed node. 76 bool insert_after(pointer p, element val) 77 { 78 if( ifree != NPTR && p != NPTR ) { 79 pointer pn = _alloc(val); 80 nextof(pn) = nextof(p); 81 nextof(p) = pn; 82 return true; 83 } 84 return false; 85 } 86 87 // insert to the position in front of p. 88 bool insert(pointer ptr, element val) 89 { 90 if( ifree == NPTR ) return false; // 没有结点,直接返回 91 if( ptr == idata ) { // 有一个节点 92 pointer np = _alloc(val); 93 nextof(np) = idata; 94 idata = np; 95 return true; 96 } 97 else { // 其他情况,先找 ptr 的前驱,再插入 98 pointer p = idata; 99 while( p != NPTR ) { 100 if( nextof(p) == ptr ) { // find p -- the prev node of ptr. 101 return insert_after(p, val); // insert val after p. 102 } 103 p = nextof(p); 104 } 105 } 106 return false; 107 } 108 109 // find element, return the prev node pointer. 110 pointer find_prev(element val) 111 { 112 pointer p = idata; 113 while( p != NPTR ) { 114 if( dataof( nextof(p) ) == val ) 115 return p; 116 p = nextof(p); 117 } 118 return NPTR; 119 } 120 121 // find element, return the node pointer. 122 pointer find(element val) 123 { 124 pointer p = idata; 125 while( p != NPTR ) { 126 if( dataof(p) == val ) return p; 127 p = nextof(p); 128 } 129 return NPTR; 130 } 131 132 // pop front element. 133 void pop_front() 134 { 135 if( idata != NPTR ) { // 将 data list 最前面的节点 移到 free list 上 136 #if 0 137 pointer p = idata; 138 idata = nextof(idata); // idata = nextof(idata); 139 nextof(p) = ifree; // SLList[p].next = ifree; 140 ifree = p; 141 #else 142 pointer p = idata; 143 idata = nextof(idata); 144 _free(p); 145 #endif 146 } 147 } 148 149 // pop back element. 150 void pop_back() 151 { 152 if( idata == NPTR ) return; 153 if( nextof(idata) == NPTR ) { // only 1 node. 154 nextof(idata) = ifree; 155 ifree = idata; 156 idata = NPTR; 157 } 158 else { // 找到最后一个节点 p,以及它的前驱 q. 159 // TODO: find the last node p, and it's perv node q. 160 pointer p = idata, q; 161 while( nextof(p) != NPTR ) { 162 q = p; 163 p = nextof( p ); 164 } 165 // remove *p to free list, update nextof(q) to NPTR. 166 nextof(p) = ifree; 167 ifree = p; 168 nextof(q) = NPTR; 169 } 170 } 171 172 void show() 173 { 174 pointer p = idata; 175 for( ; p != NPTR; p = nextof(p) ) { 176 printf(" %3d ", dataof(p) ); 177 } 178 printf("\n"); 179 } 180 181 #define INFOSHOW 182 void info() 183 { 184 #ifdef INFOSHOW 185 int i; 186 DEBUGVAL(ifree); 187 DEBUGVAL(idata); 188 puts("====================\n" 189 "index\tdata\tnext\n" 190 "--------------------"); 191 for(i=0; i<MAXN; i++) { 192 printf("%d\t%d\t%d\n", i, SLList[i].data, SLList[i].next); 193 } 194 puts("====================\n"); 195 #endif 196 } 197 198 /* 199 测试程序: 200 */ 201 int main() 202 { 203 int i; 204 init(); 205 206 #if 1 // push_front test: 207 puts("push_front test:"); 208 for(i=0; i<MAXN+2; i++) { 209 push_front(2*i+1); 210 show(); 211 } 212 213 puts("pop_front test:"); 214 for(i=0; i<MAXN+2; i++) { 215 pop_front(); 216 show(); 217 } 218 #endif 219 220 #if 1 // push_back test: 221 puts("push_back test:"); 222 for(i=0; i<MAXN+2; i++) { 223 push_back((i+1)*10); 224 show(); 225 } 226 227 puts("pop_back test:"); 228 for(i=0; i<MAXN+1; i++) 229 { 230 pop_back(); 231 show(); 232 } 233 #endif 234 235 #if 1 // insert test: 236 puts("insert test:"); 237 for(i=0; i<MAXN+2; i++) 238 { 239 insert(idata, (i+1)*10); 240 show(); 241 } 242 puts("clear...\n"); 243 clear(); 244 #endif 245 246 #if 1 // insert_after test: 247 puts("insert_after test:"); 248 push_back(-99); 249 for(i=0; i<MAXN+1; i++) { 250 insert_after(idata, i+1); 251 show(); 252 } 253 puts("clear...\n"); 254 clear(); 255 #endif 256 257 #if 1 // find test: 258 puts("find test:"); 259 for(i=0; i<MAXN/2; i++) { 260 push_front(MAXN-i); 261 push_back(MAXN/2-i); 262 //show(); 263 } 264 show(); 265 info(); 266 for(i=0; i<MAXN; i++) { 267 int val = rand()%(2*MAXN); 268 pointer p = find(val); 269 if( p != NPTR ) 270 printf("%3d %3d found at %d\n", val, dataof(p), p); 271 else 272 printf("%3d not found\n", val); 273 } 274 #endif 275 276 #if 1 277 puts("\nfind_prev test:"); 278 for(i=0; i<MAXN; i++) { 279 int val = rand()%(2*MAXN); 280 pointer p = find_prev(val); 281 if( p != NPTR ) 282 printf("%3d %3d found at %d's next.\n", val, dataof(nextof(p)), p); 283 else 284 printf("%3d not found\n", val); 285 } 286 #endif 287 288 #if 1 // find_prev and insert_after test: 289 clear(); 290 puts("\nfind_prev and insert_after test:"); 291 for(i=0; i<MAXN/2; i++) { 292 push_front(MAXN/2-i); 293 } 294 show(); 295 for(i=0; i<MAXN/2; i++) { 296 int val = rand()%(2*MAXN), n=-(i+1); 297 pointer p = find_prev(val); 298 if( p != NPTR ) { 299 printf("insert %d to front of %d:", n, val); 300 insert_after(p, n); 301 show(); 302 } 303 } 304 #endif 305 306 #if 1 // find and insert test: 307 clear(); 308 puts("\nfind and insert test:"); 309 for(i=0; i<MAXN/2; i++) { 310 push_front(MAXN/2-i); 311 } 312 show(); 313 for(i=0; i<MAXN/2; i++) { 314 int val = rand()%MAXN, n=-(i+1); 315 pointer p = find(val); 316 if( p != NPTR ) { 317 printf("insert %d to after of %d:", n, val); 318 insert_after(p, n); 319 show(); 320 } 321 } 322 #endif 323 324 puts("end of main()."); 325 return 0; 326 } 327 328 //
测试结果如下:
push_front test: 1 3 1 5 3 1 7 5 3 1 9 7 5 3 1 11 9 7 5 3 1 13 11 9 7 5 3 1 15 13 11 9 7 5 3 1 17 15 13 11 9 7 5 3 1 19 17 15 13 11 9 7 5 3 1 21 19 17 15 13 11 9 7 5 3 1 23 21 19 17 15 13 11 9 7 5 3 1 25 23 21 19 17 15 13 11 9 7 5 3 1 27 25 23 21 19 17 15 13 11 9 7 5 3 1 29 27 25 23 21 19 17 15 13 11 9 7 5 3 1 31 29 27 25 23 21 19 17 15 13 11 9 7 5 3 1 31 29 27 25 23 21 19 17 15 13 11 9 7 5 3 1 31 29 27 25 23 21 19 17 15 13 11 9 7 5 3 1 pop_front test: 29 27 25 23 21 19 17 15 13 11 9 7 5 3 1 27 25 23 21 19 17 15 13 11 9 7 5 3 1 25 23 21 19 17 15 13 11 9 7 5 3 1 23 21 19 17 15 13 11 9 7 5 3 1 21 19 17 15 13 11 9 7 5 3 1 19 17 15 13 11 9 7 5 3 1 17 15 13 11 9 7 5 3 1 15 13 11 9 7 5 3 1 13 11 9 7 5 3 1 11 9 7 5 3 1 9 7 5 3 1 7 5 3 1 5 3 1 3 1 1 push_back test: 10 10 20 10 20 30 10 20 30 40 10 20 30 40 50 10 20 30 40 50 60 10 20 30 40 50 60 70 10 20 30 40 50 60 70 80 10 20 30 40 50 60 70 80 90 10 20 30 40 50 60 70 80 90 100 10 20 30 40 50 60 70 80 90 100 110 10 20 30 40 50 60 70 80 90 100 110 120 10 20 30 40 50 60 70 80 90 100 110 120 130 10 20 30 40 50 60 70 80 90 100 110 120 130 140 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 pop_back test: 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 10 20 30 40 50 60 70 80 90 100 110 120 130 140 10 20 30 40 50 60 70 80 90 100 110 120 130 10 20 30 40 50 60 70 80 90 100 110 120 10 20 30 40 50 60 70 80 90 100 110 10 20 30 40 50 60 70 80 90 100 10 20 30 40 50 60 70 80 90 10 20 30 40 50 60 70 80 10 20 30 40 50 60 70 10 20 30 40 50 60 10 20 30 40 50 10 20 30 40 10 20 30 10 20 10 insert test: 10 20 10 30 20 10 40 30 20 10 50 40 30 20 10 60 50 40 30 20 10 70 60 50 40 30 20 10 80 70 60 50 40 30 20 10 90 80 70 60 50 40 30 20 10 100 90 80 70 60 50 40 30 20 10 110 100 90 80 70 60 50 40 30 20 10 120 110 100 90 80 70 60 50 40 30 20 10 130 120 110 100 90 80 70 60 50 40 30 20 10 140 130 120 110 100 90 80 70 60 50 40 30 20 10 150 140 130 120 110 100 90 80 70 60 50 40 30 20 10 160 150 140 130 120 110 100 90 80 70 60 50 40 30 20 10 160 150 140 130 120 110 100 90 80 70 60 50 40 30 20 10 160 150 140 130 120 110 100 90 80 70 60 50 40 30 20 10 clear... insert_after test: -99 1 -99 2 1 -99 3 2 1 -99 4 3 2 1 -99 5 4 3 2 1 -99 6 5 4 3 2 1 -99 7 6 5 4 3 2 1 -99 8 7 6 5 4 3 2 1 -99 9 8 7 6 5 4 3 2 1 -99 10 9 8 7 6 5 4 3 2 1 -99 11 10 9 8 7 6 5 4 3 2 1 -99 12 11 10 9 8 7 6 5 4 3 2 1 -99 13 12 11 10 9 8 7 6 5 4 3 2 1 -99 14 13 12 11 10 9 8 7 6 5 4 3 2 1 -99 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 -99 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 -99 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 clear... find test: 9 10 11 12 13 14 15 16 8 7 6 5 4 3 2 1 ifree: -1 idata: 14 ==================== index data next -------------------- 0 16 1 1 8 3 2 15 0 3 7 5 4 14 2 5 6 7 6 13 4 7 5 9 8 12 6 9 4 11 10 11 8 11 3 13 12 10 10 13 2 15 14 9 12 15 1 -1 ==================== 9 9 found at 14 3 3 found at 11 30 not found 4 4 found at 9 1 1 found at 15 12 12 found at 8 22 not found 14 14 found at 4 18 not found 16 16 found at 0 9 9 found at 14 17 not found 17 not found 27 not found 9 9 found at 14 11 11 found at 10 find_prev test: 19 not found 6 6 found at 3's next. 27 not found 28 not found 7 7 found at 1's next. 12 12 found at 10's next. 30 not found 25 not found 4 4 found at 7's next. 30 not found 13 13 found at 8's next. 28 not found 6 6 found at 3's next. 23 not found 7 7 found at 1's next. 30 not found find_prev and insert_after test: 1 2 3 4 5 6 7 8 insert -4 to front of 8: 1 2 3 4 5 6 7 -4 8 insert -5 to front of 3: 1 2 -5 3 4 5 6 7 -4 8 insert -8 to front of 6: 1 2 -5 3 4 5 -8 6 7 -4 8 find and insert test: 1 2 3 4 5 6 7 8 insert -2 to after of 3: 1 2 3 -2 4 5 6 7 8 insert -6 to after of 8: 1 2 3 -2 4 5 6 7 8 -6 insert -7 to after of 5: 1 2 3 -2 4 5 -7 6 7 8 -6 end of main().