註:本文的主要目的是為了記錄自己的學習過程,也方便與大家做交流。
轉載請註明來自: http://blog.csdn.net/ab198604/
最近突然間覺得應該補補IT技術的基礎的知識,因為對這些基礎知識的梳理不僅可以對自己所掌握的知識進一步鞏固,無論是提高自身的技術水平方面還是從後期就業方面,都是大有裨益的,所以還是要打好基礎,一步一個腳印才行,總之,知識需要有時間的積累。
從前自己並未系統的學習過電腦知識,對資料結構的認識也是一知半解,自從學了linux系統的一些知識之後,特別是發現在linux核心中對鏈表的運用隨處可見,由不得自己不重視,當然鏈表的運用範疇本身是非常廣泛的,如郵件清單、記憶體管理、多項式計算等,所以只要掌握了鏈表的基礎知識,就可以做到舉一反三了,對類似運用情境的鏈表代碼也就可以自然地掌握了。
鏈表其實有許多的種類:單向鏈表、雙向鏈表、單向迴圈鏈表和雙向迴圈鏈表。他們之間的複雜關係是逐步增加的,這裡主要介紹單向鏈表這種資料結構,因為它使用最為廣泛。
什麼是單向鏈表呢?
從字面上理解,那就是“單向”+“鏈表”,表明這種資料結構是有方向性的,並且只有一個方向。另外,“鏈表”表明這種資料結構是一種鏈式儲存結構,它不同於線性表的順序儲存結構。鏈表的相鄰元素在實體記憶體中不連續,所以這種結構可以充分利用一些系統的記憶體片段來完成一些事務,即如果採用鏈表結構有時可以解決當連續記憶體配置不足時的問題。既然是單向鏈表,那也意味著它是由各個元素之間通過一個指標彼此串連而組成的。每個元素包含兩部分:資料域和一個稱為next的指標域。通過採用這種結構,next的指標域將按某一個方向指向其下一個元素。最後一個元素的next指標域指向NULL,即為空白,它表示鏈表的末尾元素,鏈表的第一個元素稱為“頭”元素。鏈表的如下所示:
如所示,每個元素連結在一起形成一個鏈表。
單向鏈表的一個特性就是只能沿著next指標的方向尋找到其後續元素,如果要尋找到鏈表中的某個元素,只能從頭到尾遍曆整個鏈表。如果我們已經從頭到尾訪問到某個元素,但是此時又想訪問這個元素的前幾個元素,此時我們是無法進行訪問,因為在我們的元素中並沒有維護一個前向的連結,所以此時必須再次從頭進行遍曆操作才行。
簡單回顧完單向鏈表的基本知識點後,下面我們要真槍實彈的開練了。以下是具體的代碼,它包含三個部分,先對每個部分進行簡單的描述說明:
list.h -->主要是單向鏈表的一些介面定義
list.c -->主要是對介面定義的具體細節實現
main.c -->主要是展示鏈表的一些簡單應用
1 單鏈表的介面定義
/* * file name: list.h * author: zhm * date: 2012-12-06 */#ifndef LIST_H#define LIST_H#include <stdlib.h>/* define a struct for list element */typedef struct ListElmt_{ void *data; struct ListElmt_ *next;}ListElmt;/* define a structure for linked list */typedef struct List_{ int size; void (*match)(const void *key1, const void *key2); void (*destroy)(void *data); ListElmt *head; ListElmt *tail;}List;/* define public interface */void list_init(List *list, void(*destroy)(void *data));void list_destroy(List *list);int list_ins_next(List *list, ListElmt *elemet, const void *data);int list_rem_next(List *list, ListElmt *element, void **data);#define list_size(list) ((list)->size)#define list_head(list) ((list)->head)#define list_tail(list) ((list)->tail)#define list_is_head(list, element) ((element) == (list)->head ? 1 : 0)#define list_is_tail(list, element) ((element) == (list)->tail ? 1 : 0)#define list_data(element) ((element)->data)#define list_next(element) ((element)->next)#endif
單向鏈表的操作主要有插入,刪除結點,初始化鏈表和刪除鏈表操作。
2 單鏈表的介面實現細節
/* * filename: list.c * author: zhm * date: 2012-12-06 */#include <stdlib.h>#include <string.h>#include "list.h"/* list_init */void list_init(List *list, void (*destroy)(void *data)){ list->size = 0; list->destroy = destroy; list->head = NULL; list->tail = NULL; return;}/* list_destroy */void list_destroy(List *list){ void *data; //keep the data in the element of the list /*remove the element */ while( list_size(list) > 0 ) { if(list_rem_next(list, NULL, (void **)&data) == 0 && list->destroy != NULL) { list->destroy(data); } } memset(list, 0, sizeof(list)); return;}/* list_ins_next */int list_ins_next(List *list, ListElmt *element, const void *data){ /* Allocate storage */ ListElmt *new_element = NULL; new_element = (ListElmt *)malloc(sizeof(ListElmt)); if( new_element == NULL ) return -1; new_element->data = (void *)data; /* Insert the element into the list */ if( element == NULL ) //from head position to insert { if( list_size(list) == 0 ) //be care to tail list->tail = new_element; new_element->next = list->head; list->head = new_element; } else { if( element->next == NULL ) //be care to tail list->tail = new_element; new_element->next = element->next; element->next = new_element; } /*Adjust size */ list->size++; return 0;}/* list_rem_next */int list_rem_next(List *list, ListElmt *element, void **data){ ListElmt *old_element; //if the list is empty if( list_size(list) == 0 ) return -1; /* Remove the element from the list */ if( element == NULL ) //from head to remove { *data = list->head->data; //keep the data. old_element = list->head; list->head = list->head->next; if( list_size(list) == 1 ) //be care to the tail list->tail = NULL; } else { //if the element to be removed is NULL if( element->next == NULL ) return -1; *data = element->next->data; old_element = element->next; element->next = element->next->next; if( element->next == NULL ) //be care to the tail list->tail = element; } //free the memory free(old_element); list->size--; return 0;}
3 測試案例代碼,如下所示:
/* * filename: main.c * author:zhm * date: 2012-12-06 */#include <string.h>#include <stdlib.h>#include <stdio.h>#include "list.h"/* destroy */void destroy(void *data){ printf("in destroy\n"); free(data); return;}/* main */int main(int argc, char **argv){ ListElmt *elem_ptr = NULL; int i; int ret; int *data = NULL; /* Create a linked list */ List list_exp; /* init the list */ printf("\ninit the list:\n"); list_init(&list_exp, destroy); /* insert the element */ printf("\ncreate a list:\n"); for(i = 0; i < 10; i++ ) { data = (int *)malloc(sizeof(int)); if( data == NULL ) return -1; *data = i; list_ins_next(&list_exp, NULL, (void *)data); } /* now the list has 10 element, then traverse and print every element */ elem_ptr = list_exp.head; for( i = 0; i < 10; i++ ) { printf("%d ", *(int *)list_data(elem_ptr) ); elem_ptr = list_next(elem_ptr); } printf("\n"); /* Remove the element, its value of the data equal 4,then traverse and print again */ elem_ptr = list_exp.head; for( i = 0; i < list_size(&list_exp); i++ ) { if( *(int *)list_data(elem_ptr) == 5 ) { ret = list_rem_next(&list_exp, elem_ptr, (void **)&data); if( ret == 0 ) { destroy(data); } } elem_ptr = list_next(elem_ptr); } printf("after remove the element: value = 4\n"); //traverse and print again elem_ptr = list_exp.head; for( i = 0; i <list_size(&list_exp); i++ ) { printf("%d ", *(int *)list_data(elem_ptr) ); elem_ptr = list_next(elem_ptr); } printf("\n\n"); printf("here begin to destroy the list :\n"); //destroy the linked list list_destroy(&list_exp); return 0;}
4 顯示執行結果,如: