C言語によるヒープと二分木の実装

ヒープデータ構造の実装

ヘッダファイル定義

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

typedef int HeapValue;
typedef struct MinHeap {
    HeapValue* elements;
    int count;
    int capacity;
} MinHeap;

void HeapInitialize(MinHeap* heap);
void HeapDestroy(MinHeap* heap);
void HeapInsert(MinHeap* heap, HeapValue value);
void HeapRemoveRoot(MinHeap* heap);
HeapValue HeapGetTop(MinHeap* heap);
int HeapGetSize(MinHeap* heap);
bool HeapIsEmpty(MinHeap* heap);
void AdjustUpwards(HeapValue* array, int child_index);
void AdjustDownwards(HeapValue* array, int parent_index, int size);

実装コード

#include "heap_impl.h"

void HeapInitialize(MinHeap* heap) {
    assert(heap);
    heap->elements = NULL;
    heap->count = heap->capacity = 0;
}

void HeapDestroy(MinHeap* heap) {
    assert(heap);
    free(heap->elements);
    heap->elements = NULL;
    heap->capacity = heap->count = 0;
}

void ValueSwap(HeapValue* first, HeapValue* second) {
    HeapValue temp = *first;
    *first = *second;
    *second = temp;
}

void AdjustUpwards(HeapValue* array, int child_index) {
    assert(array);
    int parent_index = (child_index - 1) / 2;
    while (child_index > 0) {
        if (array[child_index] < array[parent_index]) {
            ValueSwap(&array[child_index], &array[parent_index]);
            child_index = parent_index;
            parent_index = (child_index - 1) / 2;
        } else {
            break;
        }
    }
}

void HeapInsert(MinHeap* heap, HeapValue value) {
    assert(heap);
    if (heap->count == heap->capacity) {
        int new_capacity = heap->capacity == 0 ? 4 : heap->capacity * 2;
        HeapValue* new_array = (HeapValue*)realloc(heap->elements, 
                                  sizeof(HeapValue) * new_capacity);
        if (new_array == NULL) {
            perror("Memory allocation failed");
            exit(EXIT_FAILURE);
        }
        heap->elements = new_array;
        heap->capacity = new_capacity;
    }
    heap->elements[heap->count] = value;
    heap->count++;
    AdjustUpwards(heap->elements, heap->count - 1);
}

void AdjustDownwards(HeapValue* array, int parent_index, int size) {
    assert(array);
    int child_index = parent_index * 2 + 1;
    while (child_index < size) {
        if (child_index + 1 < size && array[child_index] > array[child_index + 1]) {
            child_index++;
        }
        if (array[parent_index] > array[child_index]) {
            ValueSwap(&array[parent_index], &array[child_index]);
            parent_index = child_index;
            child_index = parent_index * 2 + 1;
        } else {
            break;
        }
    }
}

void HeapRemoveRoot(MinHeap* heap) {
    assert(heap);
    assert(heap->count > 0);
    ValueSwap(&heap->elements[0], &heap->elements[heap->count - 1]);
    heap->count--;
    AdjustDownwards(heap->elements, 0, heap->count);
}

HeapValue HeapGetTop(MinHeap* heap) {
    assert(heap);
    assert(heap->count > 0);
    return heap->elements[0];
}

int HeapGetSize(MinHeap* heap) {
    return heap->count;
}

bool HeapIsEmpty(MinHeap* heap) {
    return heap->count == 0;
}

ヒープソートの実装

#include <stdio.h>
#include <assert.h>

void ElementSwap(int* elem1, int* elem2) {
    int temp = *elem1;
    *elem1 = *elem2;
    *elem2 = temp;
}

void SiftDown(int* array, int size, int index) {
    int child = index * 2 + 1;
    while (child < size) {
        if (child + 1 < size && array[child + 1] > array[child]) {
            child++;
        }
        if (array[child] > array[index]) {
            ElementSwap(&array[child], &array[index]);
            index = child;
            child = index * 2 + 1;
        } else {
            break;
        }
    }
}

void HeapSortArray(int* array, int length) {
    assert(array);
    for (int i = (length - 2) / 2; i >= 0; i--) {
        SiftDown(array, length, i);
    }
    
    for (int end = length - 1; end > 0; end--) {
        ElementSwap(&array[0], &array[end]);
        SiftDown(array, end, 0);
    }
}

二分木データ構造の実装

ノード構造と基本操作

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef char TreeNodeValue;
typedef struct BinaryTreeNode {
    TreeNodeValue data;
    struct BinaryTreeNode* left;
    struct BinaryTreeNode* right;
} TreeNode;

TreeNode* TreeCreateFromPreorder(TreeNodeValue* sequence, int length, int* index);
void TreeDestroy(TreeNode** root);
int TreeCountNodes(TreeNode* root);
int TreeCountLeaves(TreeNode* root);
int TreeCountLevelNodes(TreeNode* root, int level);
TreeNode* TreeFindNode(TreeNode* root, TreeNodeValue target);
void TreePreorderTraversal(TreeNode* root);
void TreeInorderTraversal(TreeNode* root);
void TreePostorderTraversal(TreeNode* root);
void TreeLevelOrderTraversal(TreeNode* root);
int TreeIsComplete(TreeNode* root);

キュー実装(レベル順走査用)

#include "binary_tree.h"
#include <stdbool.h>

typedef TreeNode* QueueItem;
typedef struct QueueNode {
    struct QueueNode* next;
    QueueItem data;
} QueueNode;

typedef struct Queue {
    QueueNode* front;
    QueueNode* rear;
    int size;
} Queue;

void QueueInit(Queue* q);
void QueueEnqueue(Queue* q, QueueItem item);
void QueueDequeue(Queue* q);
QueueItem QueueFront(Queue* q);
int QueueSize(Queue* q);
bool QueueIsEmpty(Queue* q);
void QueueDestroy(Queue* q);

二分木操作の実装

#include "binary_tree.h"
#include "tree_queue.h"

TreeNode* CreateTreeNode(TreeNodeValue value) {
    TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));
    if (node == NULL) {
        perror("Node creation failed");
        exit(EXIT_FAILURE);
    }
    node->data = value;
    node->left = node->right = NULL;
    return node;
}

TreeNode* TreeCreateFromPreorder(TreeNodeValue* sequence, int length, int* index) {
    if (*index >= length || sequence[*index] == '#') {
        (*index)++;
        return NULL;
    }
    
    TreeNode* node = CreateTreeNode(sequence[*index]);
    (*index)++;
    
    node->left = TreeCreateFromPreorder(sequence, length, index);
    node->right = TreeCreateFromPreorder(sequence, length, index);
    
    return node;
}

int TreeCountNodes(TreeNode* root) {
    if (root == NULL) return 0;
    return TreeCountNodes(root->left) + TreeCountNodes(root->right) + 1;
}

void TreeLevelOrderTraversal(TreeNode* root) {
    Queue q;
    QueueInit(&q);
    if (root != NULL) {
        QueueEnqueue(&q, root);
    }
    
    while (!QueueIsEmpty(&q)) {
        int level_size = QueueSize(&q);
        for (int i = 0; i < level_size; i++) {
            TreeNode* current = QueueFront(&q);
            QueueDequeue(&q);
            printf("%c ", current->data);
            
            if (current->left != NULL) QueueEnqueue(&q, current->left);
            if (current->right != NULL) QueueEnqueue(&q, current->right);
        }
        printf("\n");
    }
    QueueDestroy(&q);
}

タグ: C言語 データ構造 ヒープ 二分木 アルゴリズム

7月23日 19:21 投稿