単方向連結リストの実装と操作

目録

定義

単方向連結リストの実装

ヘッダーノードなし

ヘッダーノードあり

単方向連結リストの空判定(Empty)

ヘッダーノードなし

ヘッダーノードあり

単方向連結リストの位置指定挿入(ListInsert)

ヘッダーノードなし

ヘッダーノードあり

指定ノードの後方挿入操作(InsertNextNode)

指定ノードの前方挿入操作(InsertPriorNode)

単方向連結リストの位置指定削除(ListDelete)

ヘッダーノードなし

ヘッダーノードあり

指定ノードの削除操作(DeleteNode)

単方向連結リストの位置指定検索(GetElem)

単方向連結リストの値指定検索(LocateElem)

単方向連結リストの長さ(Length)

単方向連結リストの作成

末尾挿入法

先頭挿入法

定義

線形リストの連続的ストレージ方式が単方向連結リストです。

利点:大きな連続的なメモリ領域を必要とせず、容量変更が容易 欠点:ランダムアクセスができず、ポインタを格納するため追加のメモリを消費

単方向連結リストの実装

typedef struct Node{      //単方向連結リストのノード定義 
    int value;           //各ノードがデータ要素を保持 
    struct Node *link;    //次のノードを指すポインタ 
}Node,*Chain;

単方向連結リストを表現するには、最初のノードを指すヘッドポインタLを宣言するだけです。

//単方向連結リストの最初のノードを指すポインタを宣言
Node * first;      //これはノードであることを強調
Chain list;        //これは単方向連結リストであることを強調

ヘッダーノードなし

#include<stdio.h>

typedef struct Node{      //単方向連結リストのノード定義 
    int value;           //各ノードがデータ要素を保持 
    struct Node *link;    //次のノードを指すポインタ 
}Node,*Chain;


//空の単方向連結リストを初期化
bool InitChain(Chain &list){
    list = NULL;          //空のリスト、まだノードはない 
    return true; 
}
 
int main(){
    Chain list;           //単方向連結リストを指すポインタを宣言 
    //空のリストを初期化 
    InitChain(list);      
    return 0; 
} 

ヘッダーノードあり

#include<stdio.h>

typedef struct Node{      //単方向連結リストのノード定義 
    int value;           //各ノードがデータ要素を保持 
    struct Node *link;    //次のノードを指すポインタ 
}Node,*Chain;


//単方向連結リストを初期化(ヘッダーノードあり)
bool InitChain(Chain &list){
    list = (Node *) malloc(sizeof(Node));    //ヘッダーノードを割り当て 
    if(list == NULL)                         //メモリ不足、割り当て失敗 
        return false;
    list->link = NULL;                       //ヘッダーノードの後にはまだノードがない 
    return true; 
}
 
int main(){
    Chain list;           //単方向連結リストを指すポインタを宣言 
    //空のリストを初期化 
    InitChain(list);      
    return 0; 
}

ヘッダーノードなしの場合、コード記述がより複雑になります。

最初のデータノードと後続のデータノードの処理では異なるコードロジックが必要です。

空リストと非空リストの処理では異なるコードロジックが必要です。

単方向連結リストの空判定(Empty)

ヘッダーノードなし

//単方向連結リストが空か判定
bool IsEmpty(Chain list){
    if(list == NULL)    
        return true; 
    else 
        return false;
}
//単方向連結リストが空か判定
bool IsEmpty(Chain list){
    return (list==NULL);
}

ヘッダーノードあり

//単方向連結リストが空か判定
bool IsEmpty(Chain list){
    if(list->link == NULL)    
        return true; 
    else 
        return false;
}
//単方向連結リストが空か判定
bool IsEmpty(Chain list){
    return (list->link == NULL);
}

単方向連結リストの位置指定挿入(ListInsert)

ヘッダーノードなし

//i番目の位置に要素eを挿入(ヘッダーノードなし)
bool InsertNode(Chain &list, int position, int value){
    if(position<1)
        return false;
    if(position==1){              //最初のノードへの挿入操作は他のノード操作と異なる
        Node *newNode =  (Node *) malloc(sizeof(Node));
        newNode->value = value;
        newNode->link= list;
        list = newNode;           //ヘッドポインタが新ノードを指す 
        return true;              
    } 
    Node *current;                //ポインタcurrentが現在スキャン中のノードを指す 
    int index = 1;                //現在currentの位置 
    current = list;               //currentは最初のノードを指す(ヘッダーノードではない)
    while(current!=NULL && index<position-1){//i-1番目のノードを見つけるループ 
        current=current->link;
        index++; 
    } 
    if(current==NULL)             //position値が不正
        return false;
    Node *newNode =  (Node *) malloc(sizeof(Node));
    newNode->value = value;
    newNode->link=current->link;
    current->link = newNode;      //ノードnewNodeをcurrentの後に接続 
    return true;                  //挿入成功 
}

ヘッダーノードあり

//i番目の位置に要素eを挿入(ヘッダーノードあり)
bool InsertNode(Chain &list, int position, int value){
    if(position<1)
        return false;
    Node *current;                //ポインタcurrentが現在スキャン中のノードを指す 
    int index = 0;                 //現在currentの位置 
    current = list;               //listはヘッダーノードを指し、ヘッダーノードは0番目のノード(データなし)
    while(current!=NULL && index<position-1){//i-1番目のノードを見つけるループ 
        current=current->link;
        index++; 
    } 
    if(current==NULL)             //position値が不正
        return false;
    Node *newNode =  (Node *) malloc(sizeof(Node));
    newNode->value = value;
    newNode->link=current->link;
    current->link = newNode;      //ノードnewNodeをcurrentの後に接続 
    return true;                  //挿入成功 
}

最良時間計算量:O(1)

最悪時間計算量:O(n)

平均時間計算量:O(n)

指定ノードの後方挿入操作(InsertNextNode)

//後方挿入操作:ノードpの後に要素eを挿入
bool InsertAfter(Node *current, int value){
    if(current==NULL)         
        return false;
    Node *newNode =  (Node *) malloc(sizeof(Node));
    if(newNode==NULL)           //メモリ割り当て失敗 
        return false;
    newNode->value = value;     //ノードnewNodeにデータ要素eを保存 
    newNode->link=current->link;
    current->link = newNode;    //ノードnewNodeをcurrentの後に接続 
    return true;                
}

時間計算量:O(1)

指定ノードの前方挿入操作(InsertPriorNode)

//前方挿入操作:ノードpの前に要素eを挿入
bool InsertBefore(Node *current, int value){
    if(current==NULL)         
        return false;
    Node *newNode =  (Node *) malloc(sizeof(Node));
    if(newNode==NULL)           //メモリ割り当て失敗 
        return false;
    newNode->link = current->link;
    current->link = newNode;    //ノードnewNodeをcurrentの後に接続 
    newNode->value = current->value;  //currentの要素をnewNodeにコピー 
    current->value = value;    //currentの要素をeで上書き 
    return true;                
}

時間計算量:O(1)

単方向連結リストの位置指定削除(ListDelete)

ヘッダーノードなし

bool RemoveNode(Chain &list, int position, int &value){
    if(position<1)
        return false;
    if(position==1){              //最初のノードの削除操作は他のノード操作と異なる
        Node *temp;
        temp = list;    
        value = temp->link->value;
        temp->link->value = null;
        list = temp->link;               //ヘッドポインタが新ノードを指す 
        return true;              
    } 
    Node *current;                //ポインタcurrentが現在スキャン中のノードを指す 
    int index = 0;                //現在currentの位置 
    current = list;               //listはヘッダーノードを指し、ヘッダーノードは0番目のノード(データなし)
    while(current!=NULL && index<position-1){//i-1番目のノードを見つけるループ 
        current=current->link;
        index++; 
    } 
    if(current==NULL)             //position値が不正
        return false;
    if(current->link==NULL)       //i-1番目のノードの後に他のノードがない 
        return false;
    Node *temp = current->link;   //tempを削除ノードを指すようにする 
    value = temp->value;          //valueで要素の値を返す 
    current->link = temp->link;   //ノード*tempをリンクから"切断" 
    free(temp);                   //ノードのストレージ領域を解放 
    return true;                  //削除成功 
}

ヘッダーノードあり

bool RemoveNode(Chain &list, int position, int &value){
    if(position<1)
        return false;
    Node *current;                //ポインタcurrentが現在スキャン中のノードを指す 
    int index = 0;                //現在currentの位置 
    current = list;               //listはヘッダーノードを指し、ヘッダーノードは0番目のノード(データなし)
    while(current!=NULL && index<position-1){//i-1番目のノードを見つけるループ 
        current=current->link;
        index++; 
    } 
    if(current==NULL)             //position値が不正
        return false;
    if(current->link==NULL)       //i-1番目のノードの後に他のノードがない 
        return false;
    Node *temp = current->link;   //tempを削除ノードを指すようにする 
    value = temp->value;          //valueで要素の値を返す 
    current->link = temp->link;   //ノード*tempをリンクから"切断" 
    free(temp);                   //ノードのストレージ領域を解放 
    return true;                  //削除成功 
}

最良時間計算量:O(1)

最悪時間計算量:O(n)

平均時間計算量:O(n)

指定ノードの削除操作(DeleteNode)

//指定ノードpを削除
bool RemoveNode(Node *current){
    if(current==NULL)         
        return false;
    Node *temp = current->link;   //tempを*currentの後続ノードを指すようにする 
    current->value = current->link->value; //後続ノードとデータ域を交換 
    current->link = temp->link;  //ノード*tempをリンクから"切断" 
    free(temp);                   //ノードのストレージ領域を解放 
    return true;        
}

時間計算量:O(1)

単方向連結リストの位置指定検索(GetElem)

//位置指定検索、i番目の要素を返す(ヘッダーノードあり)
Node * FindByPosition(Chain list, int position){
    if(position<1)
        return NULL;
    Node * current;               //ポインタcurrentが現在スキャン中のノードを指す
    int index = 0;                //currentの位置
    current = list;               //listはヘッダーノードを指し、ヘッダーノードは0番目のノード(データなし)
    while(current!=NULL && index<position) { //i番目のノードを見つけるループ 
        current=current->link;
        index++; 
    }
    return current;
}

時間計算量:O(n)

単方向連結リストの値指定検索(LocateElem)

//値指定検索、データ域==eのノードを見つける
Node * FindByValue(Chain list, int value){
    Node *current = list->link;
    //最初のノードからデータ域がeのノードを検索
    while (current!=NULL && current->value !=value)
        current = current->link; 
    return current;               //見つかればそのノードのポインタを返し、なければNULLを返す 
}

時間計算量:O(n)

単方向連結リストの長さ(Length)

//リストの長さを求める(ヘッダーノードあり)
int GetLength(Chain list){
    int length = 0;               //リストの長さをカウント
    Node *current =list;
    while (current->link != NULL){
        current->link;
        length++; 
    } 
    return length;
}

時間計算量:O(n)

単方向連結リストの作成

末尾挿入法

//末尾挿入法(ヘッダーノードあり)
Chain CreateByTailInsert(Chain &list){
    int input;                
    list=(Chain)malloc(sizeof(Node));    //ヘッダーノードを作成 
    Node *newNode,*tail = list;          //tailは末尾ポインタ
    scanf("%d",&input);                   //ノードの値を入力 
    while(input!=9999){                   //9999を入力すると終了 
        newNode=(Node)malloc(sizeof(Node));
        newNode->value =input;
        tail->link=newNode;
        tail = newNode;                   //tailが新しい末尾ノードを指す 
        scanf("%d",&input);
    } 
    tail->link=NULL;                      //末尾ノードのポインタをNULLに設定 
    return list;        
}

時間計算量:O(n)

先頭挿入法

//先頭挿入法(ヘッダーノードあり)
Chain CreateByHeadInsert(Chain &list){
    Node *newNode;
    int input;                
    list=(Chain)malloc(sizeof(Node));    //ヘッダーノードを作成 
    list->link=NULL;                      //初期状態で空のリスト 
    scanf("%d",&input);                   //ノードの値を入力 
    while(input!=9999){                   //9999を入力すると終了 
        newNode=(Node)malloc(sizeof(Node));  //新ノードを作成 
        newNode->value = input;
        newNode->link = list->link;
        list->link = newNode;             //新ノードをリストに挿入、listはヘッダーノード 
        scanf("%d",&input);
    } 
    return list;        
}

タグ: データ構造 連結リスト C言語

7月27日 01:05 投稿