火龙信奥
  • 首页
  • 课程
  • 题库
  • 打卡
    • 代码对战
    • 快速对战
  • 题单
  • 团队
  • 荣誉墙
  • 商城
  • 登录 / 注册

2025/26 冬季学期 第 8 次实验作业

作者: 作者的头像   huolong , 时间:2026-01-04 20:59:19 , 所有人可见, 阅读  7

动态数组和链表实现 dynarray.cpp 完整实现

/*
 * Dynamisches Array mit void* Elementen
 */
#include <iostream>
#include <cstdlib>  // für malloc, realloc, free
#include <cstddef>  // für size_t
using namespace std;

/**
 * @brief Struktur für ein dynamisches Array, das void* Zeiger speichert.
 */
struct DynamicArray {
    void** data; // Zeiger auf das Array von void-Pointern
    size_t capacity; // Aktuelle Kapazität des Arrays
    size_t count; // Anzahl der tatsächlich gespeicherten Elemente
};

/**
 * @brief Initialisiert ein leeres Array mit Kapazität 4.
 * 
 * @param arr Zeiger auf das zu initialisierende Array
 */
void init_array(DynamicArray* arr) {
    arr->capacity = 4;
    arr->count = 0;
    arr->data = (void**)malloc(arr->capacity * sizeof(void*));
}

/**
 * @brief Gibt den allokierten Speicher frei.
 * 
 * @param arr Zeiger auf das Array
 */
void destroy_array(DynamicArray* arr) {
    free(arr->data);
    arr->data = nullptr;
    arr->capacity = 0;
    arr->count = 0;
}

/**
 * @brief Fügt ein Element an der angegebenen Position ein.
 * 
 * Elemente ab dieser Position werden nach hinten verschoben.
 * Wenn die Kapazität erschöpft ist, wird sie verdoppelt.
 * 
 * @param arr Zeiger auf das Array
 * @param index Position, an der eingefügt werden soll
 * @param element Zeiger auf das hinzuzufügende Element
 * @return Zeiger auf das Element, oder nullptr bei ungültigem Index
 */
void* insert(DynamicArray* arr, size_t index, void* element) {
    // Überprüfen, ob der Index gültig ist (0 <= index <= count)
    if (index > arr->count) {
        return nullptr;
    }

    // Wenn das Array voll ist, Kapazität verdoppeln
    if (arr->count == arr->capacity) {
        arr->capacity *= 2;
        void** new_data = (void**)realloc(arr->data, arr->capacity * sizeof(void*));
        if (new_data == nullptr) {
            return nullptr; // Speicherzuweisung fehlgeschlagen
        }
        arr->data = new_data;
    }

    // Elemente ab Index um eine Position nach hinten verschieben
    for (size_t i = arr->count; i > index; i--) {
        arr->data[i] = arr->data[i-1];
    }

    // Neues Element einfügen
    arr->data[index] = element;
    arr->count++;

    return element;
}

/**
 * @brief Entfernt das Element an der angegebenen Position.
 * 
 * Nachfolgende Elemente rücken auf.
 * 
 * @param arr Zeiger auf das Array
 * @param index Position des zu löschenden Elements
 * @return Zeiger auf das Element, oder nullptr bei ungültigem Index
 */
void* remove(DynamicArray* arr, size_t index) {
    // Überprüfen, ob der Index gültig ist (0 <= index < count)
    if (index >= arr->count) {
        return nullptr;
    }

    void* removed_element = arr->data[index];

    // Elemente nach dem gelöschten Element um eine Position nach vorne verschieben
    for (size_t i = index; i < arr->count - 1; i++) {
        arr->data[i] = arr->data[i+1];
    }

    arr->count--;

    return removed_element;
}

/**
 * @brief Fügt ein Element am Anfang des Arrays hinzu.
 * 
 * @param list Zeiger auf das Array
 * @param element Zeiger auf das hinzuzufügende Element
 * @return Zeiger auf das Element, oder nullptr bei ungültigem Index
 */
void* push_front(DynamicArray* arr, void* element) {
    return insert(arr, 0, element);
}

/**
 * @brief Fügt ein Element am Ende des Arrays hinzu.
 * 
 * @param arr Zeiger auf das Array
 * @param element Zeiger auf das hinzuzufügende Element
 * @return Zeiger auf das Element, oder nullptr bei ungültigem Index
 */
void* push_back(DynamicArray* arr, void* element) {
    return insert(arr, arr->count, element);
}

/**
 * @brief Entfernt das erste Element des Arrays.
 * 
 * @param arr Zeiger auf das Array
 * @return Zeiger auf das Element, oder nullptr bei ungültigem Index
 */
void* remove_front(DynamicArray* arr) {
    return remove(arr, 0);
}

/**
 * @brief Entfernt das letzte Element des Arrays.
 * 
 * @param arr Zeiger auf das Array
 * @return Zeiger auf das Element, oder nullptr bei ungültigem Index
 */
void* remove_back(DynamicArray* arr) {
    if (arr->count == 0) return nullptr;
    return remove(arr, arr->count - 1);
}

/**
 * @brief Gibt das Element an der angegebenen Position zurück.
 * 
 * @param arr Zeiger auf das Array
 * @param index Position des Elements
 * @return Zeiger auf das Element, oder nullptr bei ungültigem Index
 */
void* get(DynamicArray* arr, size_t index) {
    if (index >= arr->count) {
        return nullptr;
    }
    return arr->data[index];
}

/**
 * @brief Gibt die Anzahl der gespeicherten Elemente zurück.
 * 
 * @param arr Zeiger auf das Array
 * @return Anzahl der Elemente
 */
size_t size(DynamicArray* arr) {
    return arr->count;
}

/**
 * @brief Gibt die aktuelle Kapazität zurück.
 * 
 * @param arr Zeiger auf das Array
 * @return Kapazität des Arrays
 */
size_t get_capacity(DynamicArray* arr) {
    return arr->capacity;
}

int main() {
    DynamicArray arr;
    init_array(&arr);

    // Testdaten
    int a = 10, b = 20, c = 30, d = 40, e = 50;

    cout << "Füge Elemente hinzu..." << endl;
    push_back(&arr, &a);
    push_back(&arr, &b);
    push_back(&arr, &c);
    push_back(&arr, &d);
    push_back(&arr, &e);

    cout << "Größe: " << size(&arr) << endl;
    cout << "Kapazität: " << get_capacity(&arr) << endl;

    cout << "\nElemente im Array:" << endl;
    for (size_t i = 0; i < size(&arr); i++) {
        int* val = (int*)get(&arr, i);
        if (val != nullptr) {
            cout << "Element " << i << ": " << *val << endl;
        }
    }

    cout << "\nEntferne Element an Index 2..." << endl;
    remove(&arr, 2);

    cout << "Elemente nach Löschung:" << endl;
    for (size_t i = 0; i < size(&arr); i++) {
        int* val = (int*)get(&arr, i);
        if (val != nullptr) {
            cout << "Element " << i << ": " << *val << endl;
        }
    }

    destroy_array(&arr);
    return 0;
}

linkedlist.cpp 完整实现

/*
 * Einfach verkettete Liste mit void* Elementen
 */
#include <iostream>
#include <cstddef>  // für size_t
using namespace std;

/**
 * @brief Struktur für einen Knoten in der verketteten Liste.
 */
struct Node {
    void* data; // Zeiger auf die gespeicherten Daten
    Node* next; // Zeiger auf den nächsten Knoten
};

/**
 * @brief Struktur für eine einfach verkettete Liste.
 * 
 * Die Liste speichert void* Zeiger und ermöglicht effizientes
 * Einfügen und Löschen von Elementen.
 */
struct LinkedList {
    Node* head; // Zeiger auf den ersten Knoten
    size_t count; // Anzahl der Elemente in der Liste
};

/**
 * @brief Initialisiert eine leere Liste.
 * 
 * @param list Zeiger auf die zu initialisierende Liste
 */
void init_list(LinkedList* list) {
    list->head = nullptr;
    list->count = 0;
}

/**
 * @brief Gibt alle Knoten frei.
 * 
 * @param list Zeiger auf die Liste
 */
void* destroy_list(LinkedList* list) {
    Node* current = list->head;
    while (current != nullptr) {
        Node* next = current->next;
        delete current;
        current = next;
    }
    list->head = nullptr;
    list->count = 0;
    return nullptr;
}

/**
 * @brief Fügt ein Element an der angegebenen Position ein.
 * 
 * @param list Zeiger auf die Liste
 * @param index Position, an der eingefügt werden soll
 * @param element Zeiger auf das hinzuzufügende Element
 * @return Zeiger auf das Element, oder nullptr bei ungültigem Index
 */
void* insert(LinkedList* list, size_t index, void* element) {
    // Überprüfen, ob der Index gültig ist (0 <= index <= count)
    if (index > list->count) {
        return nullptr;
    }

    Node* new_node = new Node;
    new_node->data = element;

    if (index == 0) {
        // Am Anfang einfügen
        new_node->next = list->head;
        list->head = new_node;
    } else {
        // Den Vorgänger des einzufügenden Knotens finden
        Node* prev = list->head;
        for (size_t i = 0; i < index - 1; i++) {
            prev = prev->next;
        }

        // Neuen Knoten einfügen
        new_node->next = prev->next;
        prev->next = new_node;
    }

    list->count++;
    return element;
}

/**
 * @brief Entfernt das Element an der angegebenen Position.
 * 
 * @param list Zeiger auf die Liste
 * @param index Position des zu löschenden Elements
 * @return Zeiger auf das Element, oder nullptr bei ungültigem Index
 */
void* remove(LinkedList* list, size_t index) {
    // Überprüfen, ob der Index gültig ist (0 <= index < count)
    if (index >= list->count) {
        return nullptr;
    }

    Node* to_remove;
    void* removed_data;

    if (index == 0) {
        // Kopf-Element entfernen
        to_remove = list->head;
        list->head = to_remove->next;
    } else {
        // Den Vorgänger des zu entfernenden Knotens finden
        Node* prev = list->head;
        for (size_t i = 0; i < index - 1; i++) {
            prev = prev->next;
        }

        // Zu entfernenden Knoten finden und entfernen
        to_remove = prev->next;
        prev->next = to_remove->next;
    }

    removed_data = to_remove->data;
    delete to_remove;
    list->count--;

    return removed_data;
}

/**
 * @brief Fügt ein Element am Anfang der Liste ein.
 * 
 * @param list Zeiger auf die Liste
 * @param element Zeiger auf das hinzuzufügende Element
 */
void* push_front(LinkedList* list, void* element) {
    return insert(list, 0, element);
}

/**
 * @brief Fügt ein Element am Ende der Liste ein.
 * 
 * @param list Zeiger auf die Liste
 * @param element Zeiger auf das hinzuzufügende Element
 */
void* push_back(LinkedList* list, void* element) {
    return insert(list, list->count, element);
}

/**
 * @brief Gibt das Element an der angegebenen Position zurück.
 * 
 * @param list Zeiger auf die Liste
 * @param index Position des Elements (0-basiert)
 * @return Zeiger auf das Element, oder nullptr bei ungültigem Index
 */
void* get(LinkedList* list, size_t index) {
    if (index >= list->count) {
        return nullptr;
    }

    Node* current = list->head;
    for (size_t i = 0; i < index; i++) {
        current = current->next;
    }

    return current->data;
}

/**
 * @brief Gibt die Anzahl der gespeicherten Elemente zurück.
 * 
 * @param list Zeiger auf die Liste
 * @return Anzahl der Elemente
 */
size_t size(LinkedList* list) {
    return list->count;
}

/**
 * @brief Entfernt das erste Element aus der Liste.
 * 
 * @param list Zeiger auf die Liste
 * @return Zeiger auf das Element, oder nullptr bei ungültigem Index
 */
void* remove_front(LinkedList* list) {
    return remove(list, 0);
}

/**
 * @brief Entfernt das letzte Element aus der Liste.
 * 
 * @param list Zeiger auf die Liste
 * @return Zeiger auf das Element, oder nullptr bei ungültigem Index
 */
void* remove_back(LinkedList* list) {
    if (list->count == 0) return nullptr;
    return remove(list, list->count - 1);
}

int main() {
    LinkedList list;
    init_list(&list);

    // Testdaten
    int a = 10, b = 20, c = 30, d = 40;

    cout << "Füge Elemente hinzu..." << endl;
    push_back(&list, &a);
    push_back(&list, &b);
    push_front(&list, &c);
    push_back(&list, &d);

    cout << "Größe: " << size(&list) << endl;

    cout << "\nElemente in der Liste:" << endl;
    for (size_t i = 0; i < size(&list); i++) {
        int* val = (int*)get(&list, i);
        if (val != nullptr) {
            cout << "Element " << i << ": " << *val << endl;
        }
    }

    cout << "\nEntferne erstes Element..." << endl;
    remove_front(&list);
    cout << "Neue Größe: " << size(&list) << endl;

    cout << "\nElemente nach Löschung:" << endl;
    for (size_t i = 0; i < size(&list); i++) {
        int* val = (int*)get(&list, i);
        if (val != nullptr) {
            cout << "Element " << i << ": " << *val << endl;
        }
    }

    destroy_list(&list);
    return 0;
}

主要实现细节说明 动态数组 (DynamicArray) 内存管理: 使用malloc初始化内存,realloc扩容,free释放 扩容策略:容量翻倍(从4开始) 注意:realloc可能返回新地址,必须更新data指针 插入操作: 检查索引有效性(0 ≤ index ≤ count) 如果需要,先扩容 将index及之后的元素后移 插入新元素,count增加 删除操作: 检查索引有效性(0 ≤ index < count) 保存要删除的元素 将删除位置之后的元素前移 count减少 返回被删除的元素 链表 (LinkedList) 节点结构: 每个节点包含数据指针和指向下一个节点的指针 使用new/delete管理内存 插入操作: 处理两种情况:在头部插入(index=0)和在中间/尾部插入 在头部插入:新节点的next指向当前head,更新head 在其他位置:找到前驱节点,调整指针 删除操作: 处理两种情况:删除头部节点(index=0)和删除其他节点 删除头部:更新head为head->next 删除其他节点:找到前驱节点,调整指针 释放被删除节点的内存 返回被删除元素的指针 内存清理: destroy_list遍历整个链表,逐个释放节点 重置head和count

—— 本文来自火龙信奥(义乌睿码科技):义乌青少年信息学奥赛与编程教育平台,专注 CSP-J/S、NOIP、GESP 竞赛培训,线上线下融合教学,助力编程升学。网址:hlcoding.com

©2026加盟我们 | 关于我们 | ACM课程 | 常见问题 | 成果墙 | 评测记录 | 浙ICP备2021013995号
在线画图 | OI WIki | 打字练习
火龙信奥
请输入登录信息


请完成安全验证
验证码底图 滑块
向右拖动滑块完成验证
请输入用户名 / 绑定的手机号码



请输入注册信息(手机号验证码注册)





验证码5分钟有效,60秒内不可重复获取,每日最多3次

微信登录

微信登录二维码

正在生成二维码...

账号已过期,请续期。
去续期

绑定手机号

📱

为了更好地保护您的账号安全,享受完整的平台服务

请您尽快绑定手机号码