0
1

More than 1 year has passed since last update.

双方向リストを使って入れ子になった関数の管理方法

Posted at

前回

双方向リストを使った引数に関数を持った関数の管理方法

voidポインタ型を戻り値とした関数

今回

 前回は、引数に関数を持つ関数uをHello構造体の中に作って、関数f内でその引数関数を呼び出して再帰的処理をしました。
 今回は、Hello_Variable構造体に初期化関数vを追加して、初期化関数vを実行した後にHello構造体の関数uを実行します。伴って、Hello_Variable構造体、executeListFunction関数、main関数を修正し、f_u関数、f_v関数を追加しました。

参考ページ

モノづくりC言語塾 C言語 関数ポインタ【ポインタを使って関数を呼ぶ仕組み解説】

超初心者向けプログラミング入門【構造体】

SAMEBASE サメベース 【[C言語]双方向リストとその基本操作(追加、削除、挿入)関数の実装[コード付]】

日々量産 【C言語でvectorさせろ】

Programming Place Plus 【連結リスト②(双方向・循環) | Programming Place Plus アルゴリズムとデータ構造編【データ構造】 第4章】

参考文献

問題解決力を鍛える!アルゴリズムとデータ構造 (KS情報科学専門書)
大槻兼資・著 秋葉拓哉・監修

[改訂新版]C言語による標準アルゴリズム事典
奥村晴彦 著

準備

今回はオンラインコンパイラを使用します。
オンラインコンパイラ

ソースコード

sample.c
#include <stdio.h>
#include <stdlib.h>

//Hello_Variable型を定義する
typedef struct Hello_Variable {
    long i;
    double d[11];
    struct Hello_Variable* (*v)(struct Hello_Variable*);
}Hello_Variable;

//関数fを代入することを想定して、関数ポインタfupo型を定義する
typedef Hello_Variable* (*fupo_v)(Hello_Variable*);

//関数fを代入することを想定して、fupo型の変数uを構造体Hello型の内に定義する
typedef struct Hello {
    long searchKey;
	Hello_Variable j;
	struct Hello* (*u)(struct Hello*);//引数に関数ポインタを持つ関数ポインタu
}Hello;

//関数fを代入することを想定して、関数ポインタfupo型を定義する
typedef Hello* (*fupo_u)(Hello* v);

// ノードの構造体
typedef struct Node {
    long type;
    void *data;
    struct Node* next;
    struct Node* prev;
}Node;

// 新しいノードを作成する関数
struct Node* createNode(void *data,long type) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    if (newNode == NULL) {
        printf("メモリの割り当てに失敗しました\n");
        exit(1);
    }
    newNode->type = type;
    newNode->data = data;
    newNode->next = NULL;
    newNode->prev = NULL;
    return newNode;
}

// リストの先頭にノードを挿入する関数
void insertAtBeginning(struct Node** head, void *data, long type) {
    struct Node* newNode = createNode(data,type);
    newNode->next = *head;
    if (*head != NULL) {
        (*head)->prev = newNode;
    }
    *head = newNode;
}

// リストの末尾にノードを挿入する関数
void insertAtEnd(struct Node** head, void *data, long type) {
    struct Node* newNode = createNode(data,type);
    struct Node* current = *head;
    if (current == NULL) {
        *head = newNode;
    } else {
        while (current->next != NULL) {
            current = current->next;
        }
        current->next = newNode;
        newNode->prev = current;
    }
}

// リストから指定したノードを削除する関数
void deleteNode(struct Node** head, struct Node* target) {
    if (*head == NULL || target == NULL) {
        return; // リストが空または対象ノードが存在しない場合は何もしない
    }

    // 対象ノードの前後のノードを連結
    if (target->prev != NULL) {
        target->prev->next = target->next;
    } else {
        *head = target->next; // 対象ノードが先頭の場合
    }

    if (target->next != NULL) {
        target->next->prev = target->prev;
    }

    free(target); // ノードを解放
}

// リスト内で特定の要素を探す関数
struct Node* search(struct Node* head, long key) {
    struct Node* current = head;
    while (current != NULL) {
        if(current->type==0){
            if (((Hello*)current->data)->searchKey == key) {
                return current;//ノードが見つかった場合、そのノードを返す
            }
        }
        current = current->next;
    }
    return NULL; // ノードが見つからなかった場合、NULLを返す
}

// リストを表示する関数
void printList(struct Node* head) {
    struct Node* current = head;
    while (current != NULL) {
        if(current->type==0){
            //Hello型関数ポインタuを実行
            printf("%ld, ", ((Hello*)current->data)->searchKey);
            //Hello_Variable型変数j.iを表示
            printf("%ld -> ", ((Hello*)current->data)->j.i);
        }
        current = current->next;
    }
    printf("NULL\n");
}

// リストを表示する関数
void executeListFunction(struct Node* head) {
    struct Node* current = head;
    while (current != NULL) {
        if(current->type==0){
            //Hello型関数ポインタj.vを実行
            ((Hello*)current->data)->j.v(&((Hello*)current->data)->j);
            //Hello型関数ポインタuを実行
            ((Hello*)current->data)->u((Hello*)current->data);
            //Hello_Variable型変数j.iを表示
            printf(",%ld -> ", ((Hello*)current->data)->j.i);
        }
        current = current->next;
    }
    printf("NULL\n");
}

Hello_Variable* f_v(Hello_Variable* q){
	//引数v->dに値を代入
	q->d[q->i]=0;
	//引数v->dを表示
	printf("_%1.2lf_",q->d[q->i]);
	//引数v->iに1を加算
	q->i++;
	if(q->i<=10){
		//引数iが10以下のとき引数関数v->uを再帰呼び出し
		q=q->v(q);
	}
	else{
	    //変数q->iを初期化
	    q->i=0;
	    //改行
	    printf("\n");
		//引数iが10より上になったらHELLO_VARIABLEポインタ型vを返す
		return q;
	}
	return q;
}

Hello* f_u(Hello* v){
	//引数v->dに値を代入
	v->j.d[v->j.i]=1+(v->j.i*0.1);
	//引数v->dを表示
	printf("_%1.2lf_",v->j.d[v->j.i]);
	//引数v->iに1を加算
	v->j.i++;
	if(v->j.i<=10){
		//引数iが10以下のとき引数関数v->uを再帰呼び出し
		v=v->u(v);
	}
	else{
	    printf("\n");
		//引数iが10より上になったらHELLO_VARIABLEポインタ型vを返す
		return v;
	}
	return v;
}


int main() {
    struct Node* myList = NULL;
    Hello data[4];
    fupo_v q=f_v;
    fupo_u r=f_u;
    int i=0;
    for(;i<4;i++){
        //Hello_Variable型変数j.iに0を代入
        data[i].j.i=0;
        //searchKeyに検索キー番号を代入
        data[i].searchKey=i;
        //関数f_uを代入
        data[i].u=r;
        //関数f_vを代入
        data[i].j.v=q;
    }
    
    
    // リストに要素を追加
    insertAtBeginning(&myList, &data[0],0);
    insertAtBeginning(&myList, &data[1],0);
    insertAtBeginning(&myList, &data[2],0);
    insertAtEnd(&myList, &data[3],0);

    // リストの関数を実行
    executeListFunction(myList);
    // リストを表示
    printf("双方向リスト: ");
    printList(myList);

    int searchKey = 2;
    struct Node* foundNode = search(myList, searchKey);
    if (foundNode != NULL) {
        printf("%ld が見つかりました\n", searchKey);
    } else {
        printf("%ld は見つかりませんでした\n", searchKey);
    }

    if (foundNode != NULL) {
        // ノードを削除
        deleteNode(&myList, foundNode);

        // リストを再度表示
        printf("削除後の双方向リスト: ");
        printList(myList);
    }

    return 0;
}

実行結果

console
_0.00__0.00__0.00__0.00__0.00__0.00__0.00__0.00__0.00__0.00__0.00_
_1.00__1.10__1.20__1.30__1.40__1.50__1.60__1.70__1.80__1.90__2.00_
,11 -> _0.00__0.00__0.00__0.00__0.00__0.00__0.00__0.00__0.00__0.00__0.00_
_1.00__1.10__1.20__1.30__1.40__1.50__1.60__1.70__1.80__1.90__2.00_
,11 -> _0.00__0.00__0.00__0.00__0.00__0.00__0.00__0.00__0.00__0.00__0.00_
_1.00__1.10__1.20__1.30__1.40__1.50__1.60__1.70__1.80__1.90__2.00_
,11 -> _0.00__0.00__0.00__0.00__0.00__0.00__0.00__0.00__0.00__0.00__0.00_
_1.00__1.10__1.20__1.30__1.40__1.50__1.60__1.70__1.80__1.90__2.00_
,11 -> NULL
双方向リスト: 2, 11 -> 1, 11 -> 0, 11 -> 3, 11 -> NULL
2 が見つかりました
削除後の双方向リスト: 1, 11 -> 0, 11 -> 3, 11 -> NULL

0
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1