前回
今回
前回は、双方向リストの追加のアルゴリズムを用いて、関数ポインタを構造体内に定義した構造体をリストに追加する操作を行いました。
今回は、双方向リストから検索番号を用いて、目的の構造体のポインタを検索します。加えて、目的の構造体を削除します。これらのアルゴリズムの実装を前回のソースコードに追加しました。
参考ページ
モノづくりC言語塾 C言語 関数ポインタ【ポインタを使って関数を呼ぶ仕組み解説】
SAMEBASE サメベース 【[C言語]双方向リストとその基本操作(追加、削除、挿入)関数の実装[コード付]】
Programming Place Plus 【連結リスト②(双方向・循環) | Programming Place Plus アルゴリズムとデータ構造編【データ構造】 第4章】
参考文献
問題解決力を鍛える!アルゴリズムとデータ構造 (KS情報科学専門書)
大槻兼資・著 秋葉拓哉・監修
準備
今回はオンラインコンパイラを使用します。
オンラインコンパイラ
ソースコード
sample.c
#include <stdio.h>
#include <stdlib.h>
//Hello_Variable型を定義する
typedef struct Hello_Variable {
long i;
double d[11];
}Hello_Variable;
//関数fを代入することを想定して、関数ポインタfupo型を定義する
typedef void (*fupo)(Hello_Variable*);
//関数fを代入することを想定して、fupo型の変数uを構造体Hello型の内に定義する
typedef struct Hello {
long searchKey;
Hello_Variable j;
fupo u;
}Hello;
// ノードの構造体
typedef struct Node {
Hello data;
struct Node* next;
struct Node* prev;
}Node;
// 新しいノードを作成する関数
struct Node* createNode(Hello data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
if (newNode == NULL) {
printf("メモリの割り当てに失敗しました\n");
exit(1);
}
newNode->data = data;
newNode->next = NULL;
newNode->prev = NULL;
return newNode;
}
// リストの先頭にノードを挿入する関数
void insertAtBeginning(struct Node** head, Hello data) {
struct Node* newNode = createNode(data);
newNode->next = *head;
if (*head != NULL) {
(*head)->prev = newNode;
}
*head = newNode;
}
// リストの末尾にノードを挿入する関数
void insertAtEnd(struct Node** head, Hello data) {
struct Node* newNode = createNode(data);
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, int key) {
struct Node* current = head;
while (current != NULL) {
if (current->data.searchKey == key) {
return current; // ノードが見つかった場合、そのノードを返す
}
current = current->next;
}
return NULL; // ノードが見つからなかった場合、NULLを返す
}
// リストを表示する関数
void printList(struct Node* head) {
struct Node* current = head;
while (current != NULL) {
//Hello型関数ポインタuを実行
printf("%ld, ", current->data.searchKey);
//Hello_Variable型変数j.iを表示
printf("%ld -> ", current->data.j.i);
current = current->next;
}
printf("NULL\n");
}
// リストを表示する関数
void executeListFunction(struct Node* head) {
struct Node* current = head;
while (current != NULL) {
//Hello型関数ポインタuを実行
current->data.u(¤t->data.j);
//Hello_Variable型変数j.iを表示
printf(",%ld -> ", current->data.j.i);
current = current->next;
}
printf("NULL\n");
}
void f(Hello_Variable* v){
//引数v->dに値を代入
v->d[v->i]=1+(v->i*0.1);
//引数v->dを表示
printf("_%1.2lf_",v->d[v->i]);
//引数v->iに1を加算
v->i++;
if(v->i<=10){
//引数iが10以下のとき関数fを再帰呼び出し
f(v);
}
else{
printf("\n");
//引数iが10より上になったらHELLO_VARIABLEポインタ型vを返す
return;
}
return;
}
int main() {
struct Node* myList = NULL;
Hello data[4];
int i=0;
for(;i<4;i++){
//Hello_Variable型変数j.iに0を代入
data[i].j.i=0;
//searchKeyに検索キー番号を代入
data[i].searchKey=i;
//関数fを代入
data[i].u=f;
}
// リストに要素を追加
insertAtBeginning(&myList, data[0]);
insertAtBeginning(&myList, data[1]);
insertAtBeginning(&myList, data[2]);
insertAtEnd(&myList, data[3]);
// リストの関数を実行
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
_1.00__1.10__1.20__1.30__1.40__1.50__1.60__1.70__1.80__1.90__2.00_
,11 -> _1.00__1.10__1.20__1.30__1.40__1.50__1.60__1.70__1.80__1.90__2.00_
,11 -> _1.00__1.10__1.20__1.30__1.40__1.50__1.60__1.70__1.80__1.90__2.00_
,11 -> _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