諸如BASIC和FORTRAN等許多語言都不支持指針。如果需要鏈表而又不能使用指針,這時我們可以使用游標(cursor)實現法來實現鏈表。
在鏈表的實現中有兩個重要的特點:
數據存儲在一組結構體中。每一個結構體包含有數據以及指向下一個結構體的指針。
一個新的結構體可以通過調用malloc而從系統全局內存(global memory)得到,並可以通過free而被釋放。
游標法必須能夠模仿實現這兩條特性:
定義一個全局的結構體數組(模擬系統全局內存)。對於數組中的任何單元,其數組下標可以用來代表一個地址。
typedef int ptr_to_node; typedef ptr_to_node list; typedef ptr_to_node position; struct node { element_type element; position next; }; struct node cursor_space[spacesize];
在這個全局的結構體數組中,保留一個表freelist作為備用單鏈表,用來malloc或free游標可用空間,該表用0作為表頭。剛開始時,freelist就是整個結構體數組。
需要理解的是:所有的鏈表,包括備用表和已用表,全部都在我們定義的全局結構體數組中,只是它們的表頭不同,從不同的表頭出發形成了不同的單鏈表。
假設我們定義了一個大小為11的游標空間,其初始化狀態如下:
Slot | Element | Next |
0 1 2 3 4 5 6 7 8 9 10 |
1 2 3 4 5 6 7 8 9 10 0 |
注:對於Next, 0的值等價於NULL指針。
上面的狀態用鏈表形式表示為:cursor_space[0]—>cursor_space[1]—>cursor_space[2]—>cursor_space[3]—>cursor_space[4]—>cursor_space[5]—>cursor_space[6]—>cursor_space[7]—>cursor_space[8]—>cursor_space[9]—>cursor_space[10]—>NULL.
為執行malloc功能,將(在表頭后面的)第一個元素從freelist中刪除。為了執行free功能,我們將該單元放在freelist的前端。
malloc和free的游標實現如下:
static position cursor_alloc(void) { position p; p = cursor_space[0].next; cursor_space[0].next = cursor_space[p].next; return p; } static void cursor_free(position p) { cursor_space[p].next = cursor_space[0].next; cursor_space[0].next = p; }
為加深理解,請參考如下實例:
Slot | Element | Next |
0 1 2 3 4 5 6 7 8 9 10 |
- b f header - header - c d e a |
6 9 0 7 0 10 4 8 2 0 1 |
如果單鏈表L的值是5,M的值是3,我們又規定了freelist表頭為0,因此,從上表中我們可以得到三個鏈表:
freelist:cursor_space[0]—>cursor_space[6]—>cursor_space[4]—>NULL
L:header—>a—>b—>e—>NULL
M:header—>c—>d—>f—>NULL
freelist是分配L、M鏈表后還剩余的可分配空間。
游標實現
/* return ture if L is empty */ int isempty(list L) { return cursor_space[L].next = 0; }
/* return true if P is the last position in list L */ int islast(position p, list L) { return cursor_space[P].next == 0; }
/* return position of X in L; 0 if not found */ /* uses a header node */ position find(element_type X, list L) { position p; p = cursor_space[L].next; while(p && cursor_space[p].element != X) p = cursor_space[p].next; return p; }
/* delete first occurence of X from a list */ /* assume use of a header node */ void delete(element_type X, list L) { position p, tmpcell; p = find_previous(X, L); if(!islast(p, L)) { tmpcell = cursor_space[p].next; cursor_space[p].next = cursor_space[tmpcell].next; cursor_free(tmpcell); } }
/* insert (after legal position P) */ void insert(element_type X, list L, position P) { position tmpcell; tmpcell = cursor_alloc(); if(tmpcell == 0) fatal_error("out of sapce!!!"); cursor_space[tmpcell].element = X; cursor_space[tmpcell].next = cursor_space[P].next; cursor_space[P].next = tmpcell; }