スポンサーリンク
連結リスト(双方向)でpushとpopをc言語で実装
連結リスト(双方向)でpushとpopをc言語で実装してみました。
下記の記事で、連結リスト(片方向)でpush/popを実装しています。
参考:連結リスト(片方向)でpushとpopをc言語で実装(サンプルコードあり)
まずは、双方向リストを構造体で定義します。
前後のノードへのポインタをメンバ変数に持つようにします。
リストの構造体には、先頭のノードのポインタをメンバ変数に定義します。。
typedef struct node{ int data; struct node* pPreNode; struct node* pNextNode; }node_t; typedef struct list{ node_t* pTopNode; }list_t;
続いて、下記は初期化関数です。
最初のノードをmalloc()で確保します。
pNextNodeとpPreNodeにはNULLを代入します。
node_t* initNode(int data){ node_t* pNode = NULL; pNode = (node_t*)malloc(sizeof(node_t)); if(pNode == NULL){ printf("malloc error\n"); return NULL; } pNode->data = data; pNode->pPreNode = NULL; pNode->pNextNode = NULL; return pNode; } list_t* initList(int data){ list_t* pList = NULL; pList = (list_t*)malloc(sizeof(list_t)); if(pList == NULL){ printf("init list malloc error\n"); return NULL; } pList->pTopNode = initNode(data); if(pList->pTopNode == NULL){ printf("init node error\n"); free(pList); return NULL; } printfList(pList); return pList; }
push関数になります。
while()で終端ノードを探索します。
新規で作成したノードのポインタを、終端ノードのpNextNodeに格納します。
また、新規で追加したノードのpPreNodeに、終端ノードだったノードへのポインタを格納します。
void push(list_t* pList, int data){ node_t* pNode = NULL; node_t* pNewNode = NULL; if(pList == NULL){ printf("NULL chk error\n"); return; } //リストが空の場合はノードを生成 if(pList->pTopNode == NULL){ pList->pTopNode = initNode(data); if(pList->pTopNode == NULL){ printf("push error\n"); } printfList(pList); return; } pNode = pList->pTopNode; while(pNode->pNextNode != NULL){ pNode = pNode->pNextNode; }; pNewNode = initNode(data); if(pNewNode == NULL){ printf("push erro\n"); return; } pNode->pNextNode = pNewNode; pNewNode->pPreNode = pNode; printfList(pList); return; }
pop関数になります。
while()で終端ノードを探索します。
終端ノードをfree()して、終端ノードの一つ前のpNextNodeにNULLを格納します。
void pop(list_t* pList){ node_t* pNode = NULL; if(pList == NULL){ printf("NULL chk error\n"); return; } if(pList->pTopNode == NULL){ printf("list empty\n"); return; } pNode = pList->pTopNode; while(pNode->pNextNode != NULL){ pNode = pNode->pNextNode; } //リストが空になった場合の処理 if(pNode == pList->pTopNode){ pList->pTopNode = NULL; free(pNode); return; } pNode->pPreNode->pNextNode = NULL; free(pNode); printfList(pList); return; }
最後に、リストをfree()してメモリ解放する関数になります。
各ノードを先頭から解放して、最後にリストを解放します。
void deleteList(list_t* pList){ node_t* pPreNode = NULL; node_t* pNode = NULL; if(pList == NULL){ printf("NULL chk error\n"); return; } pPreNode = pList->pTopNode; pNode = pList->pTopNode; while(pNode != NULL){ pPreNode = pNode; pNode = pNode->pNextNode; free(pPreNode); } free(pList); return; }
スポンサーリンク
サンプルコード
下記がサンプルコードになります。
main()関数では、動作確認も兼ねていたので、push/popを複数回繰り返しています。
呼び出し元でのエラーチェックは今回は行っていません。
$ cat sample.c #include <stdio.h> #include <stdlib.h> typedef struct node{ int data; struct node* pPreNode; struct node* pNextNode; }node_t; typedef struct list{ node_t* pTopNode; }list_t; void printfList(list_t* pList){ node_t* pNode = pList->pTopNode; if(pList == NULL){ printf("NULL chk error\n"); return; } while(pNode != NULL){ printf("%d ", pNode->data); pNode = pNode->pNextNode; }; printf("\n"); return; } node_t* initNode(int data){ node_t* pNode = NULL; pNode = (node_t*)malloc(sizeof(node_t)); if(pNode == NULL){ printf("malloc error\n"); return NULL; } pNode->data = data; pNode->pPreNode = NULL; pNode->pNextNode = NULL; return pNode; } list_t* initList(int data){ list_t* pList = NULL; pList = (list_t*)malloc(sizeof(list_t)); if(pList == NULL){ printf("init list malloc error\n"); return NULL; } pList->pTopNode = initNode(data); if(pList->pTopNode == NULL){ printf("init node error\n"); free(pList); return NULL; } printfList(pList); return pList; } void push(list_t* pList, int data){ node_t* pNode = NULL; node_t* pNewNode = NULL; if(pList == NULL){ printf("NULL chk error\n"); return; } //リストが空の場合はノードを生成 if(pList->pTopNode == NULL){ pList->pTopNode = initNode(data); if(pList->pTopNode == NULL){ printf("push error\n"); } printfList(pList); return; } pNode = pList->pTopNode; while(pNode->pNextNode != NULL){ pNode = pNode->pNextNode; }; pNewNode = initNode(data); if(pNewNode == NULL){ printf("push erro\n"); return; } pNode->pNextNode = pNewNode; pNewNode->pPreNode = pNode; printfList(pList); return; } void pop(list_t* pList){ node_t* pNode = NULL; if(pList == NULL){ printf("NULL chk error\n"); return; } if(pList->pTopNode == NULL){ printf("list empty\n"); return; } pNode = pList->pTopNode; while(pNode->pNextNode != NULL){ pNode = pNode->pNextNode; } //リストが空になった場合の処理 if(pNode == pList->pTopNode){ pList->pTopNode = NULL; free(pNode); return; } pNode->pPreNode->pNextNode = NULL; free(pNode); printfList(pList); return; } void deleteList(list_t* pList){ node_t* pPreNode = NULL; node_t* pNode = NULL; if(pList == NULL){ printf("NULL chk error\n"); return; } pPreNode = pList->pTopNode; pNode = pList->pTopNode; while(pNode != NULL){ pPreNode = pNode; pNode = pNode->pNextNode; free(pPreNode); } free(pList); return; } int main(){ list_t* pList = NULL; pList = initList(1); push(pList,2); push(pList,3); pop(pList); push(pList,3); pop(pList); pop(pList); pop(pList); pop(pList); push(pList,1); push(pList,2); pop(pList); pop(pList); pop(pList); push(pList,1); push(pList,2); push(pList,3); deleteList(pList); pList = initList(1); push(pList,2); pop(pList); pop(pList); pop(pList); deleteList(pList); return 0; }
下記が実行結果になります。
$ gcc sample.c -o sample $ ./sample 1 1 2 1 2 3 1 2 1 2 3 1 2 1 list empty 1 1 2 1 list empty 1 1 2 1 2 3 1 1 2 1 list empty
スポンサーリンク