単方向リスト(Singly Linked List)
1.単方向リスト(Singly Linked List)とは
別名「線形リスト(Linear List)」又は「連結リスト」とよばれ、データ構造の基本アルゴリズムの一つです。
例えば、下の図のようなイメージです。
リスト構造
Head データ1のアドレス | 
-> | 
データ1 データ2のアドレス | 
-> | 
データ2 データ3のアドレス | 
-> | 
データ3 NULL | 
Headとは、リストの先頭のデータのアドレスを示します。ここが「NULL」の場合、データは存在しないと言う事が一般的です。
そして「データ x」が「次のデータ xへのアドレス」を格納して単方向リストを形成します。
また「データ x」の「次のデータ xのアドレス」を格納している変数が「NULL」の場合リスト構造の最後を示します。
 
2.先頭にデータを追加
- 新規データの「次のデータのアドレス」にHeadが示す「次のデータのアドレス」を代入
 
- 新規データのアドレスを「Head」に代入
 
実行前
Head データ1のアドレス | 
-> | 
データ1 データ2のアドレス | 
-> | 
データ2 NULL | 
実行後
Head 新規データアドレス | 
-> | 
新規データ データ1のアドレス | 
-> | 
データ1 データ2のアドレス | 
-> | 
データ2 NULL | 
void HeadInsert(LIST **Head, LIST *Node)
{
    /* データを追加 */
    Node->next = *Head;
    *Head = Node;
}
 
3.最後にデータを追加
- リストにデータが無ければ、先頭にデータを追加し終了
 
- リストの最後のデータを検索
 
- 最後のデータに新規データのアドレスを代入
 
- 新規データに「NULL」を代入
 
実行前
Head データ1のアドレス | 
-> | 
データ1 データ2のアドレス | 
-> | 
データ2 NULL | 
実行後
Head データ1のアドレス | 
-> | 
データ1 データ2のアドレス | 
-> | 
データ2 新規データアドレス | 
-> | 
新規データ NULL | 
void TailInsert(LIST **Head, LIST *Node)
{
    LIST *p;
    
    if(*Head == (LIST *)NULL){
        /* リストにデータが無い場合、先頭に追加 */
        HeadInsert(Head, Node);
    }else{
        /* リストの最後を検索 */
        for(p=*Head; p->next!=(LIST *)NULL; p=p->next); 
        
        /* データを追加 */
        p->next = Node;
        Node->next = NULL;
    }
}
 
4.データの挿入
- 挿入位置を検索
 
- 新規データの「次のデータのアドレス」に挿入位置のデータに代入されている「次のデータのアドレス」を代入
 
- 挿入位置のデータの「次のデータのアドレス」に新規データのアドレスを代入
 
実行前
Head データ1のアドレス | 
-> | 
データ1 データ2のアドレス | 
-> | 
データ2 NULL | 
実行後
Head データ1のアドレス | 
-> | 
データ1 新規データアドレス | 
-> | 
新規データ データ2のアドレス | 
-> | 
データ2 NULL | 
void ListInsert(LIST **Head, LIST *Node, int Position)
{
    LIST *p;
    /* 挿入位置の一つ前にする*/
    Position--;
    /* 挿入位置が先頭なら */
    if(*Head == (LIST *)NULL || Position<=0){
        HeadInsert(Head, Node);
    /* 挿入位置は先頭でない */
    }else{
        /* 挿入位置がリストの最後より後ろなら */
        if(GetNodeTotal(Head)<Position){
            TailInsert(Head, Node);
        }else{
            /* 挿入位置のNodeを取得 */
            p=GetNode(Head, Position);
            /* データを挿入 */
            Node->next = p->next;
            p->next = Node;
        }
    }
}
 
5.データの削除
- 1.削除データの位置を検索
 
- 削除データのアドレスが格納されているデータに削除データに代入されている「次のデータのアドレス」代入
 
実行前
Head データ1のアドレス | 
-> | 
データ1 削除データアドレス | 
-> | 
削除データ データ2のアドレス | 
-> | 
データ2 NULL | 
実行後
Head データ1のアドレス | 
-> | 
データ1 データ2のアドレス | 
-> | 
データ2 NULL | 
void DeleteNode(LIST **Head, int Position)
{
    LIST *p, *Node;
    /* 削除位置の一つ前にする */
    Position--;
    /* LISTが存在しないなら終了 */
    if(*Head != (LIST *)NULL){
        /* 削除位置が先頭なら解放 */
        if(Position==0){
            p=*Head;
            *Head = p->next;
            NodeFree(p);
        /* 削除位置がList内なら */
        }else if(GetNodeTotal(Head)>Position && Position>0){
            /* 削除位置のNodeを取得 */
            p=GetNode(Head, Position);
            /* Nodeを解放する */            
            Node = p->next;
            p->next = Node->next;
            NodeFree(Node);
        }
    }
}
 
サンプル
以下のリンクからサンプルを閲覧又はダウンロードできます。
このサンプルはSHIFT-JISで書かれております。