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

// 定义双向链表的节点结构体
typedef struct Node {
    int data;           // 数据域,用于存储节点的值
    struct Node* prev;  // 指向前一个节点的指针
    struct Node* next;  // 指向后一个节点的指针
} Node;

// 创建一个新节点
Node* createNode(int data) {
    Node* newNode = (Node*)malloc(sizeof(Node)); // 分配内存
    if (newNode == NULL) {
        printf("Memory allocation failed.\n"); // 如果内存分配失败,打印错误消息
        exit(1); // 终止程序
    }
    newNode->data = data; // 设置节点存储的数据
    newNode->prev = NULL; // 新节点的前指针设置为 NULL
    newNode->next = NULL; // 新节点的后指针设置为 NULL
    return newNode; // 返回新创建的节点
}

// 插入节点到链表头部
void insertAtHead(Node** head, int data) {
    Node* newNode = createNode(data); // 创建一个新节点
    if (*head == NULL) { // 检查链表是否为空
        *head = newNode; // 如果是空的,新节点就是头节点
        return;
    }
    newNode->next = *head; // 将新节点的下一个指向当前头节点
    (*head)->prev = newNode; // 将当前头节点的前一个指向新节点
    *head = newNode; // 更新头节点为新节点
}

// 插入节点到链表尾部
void insertAtTail(Node** head, int data) {
    Node* newNode = createNode(data); // 创建一个新节点
    if (*head == NULL) { // 如果链表为空
        *head = newNode; // 新节点成为头节点
        return;
    }
    Node* temp = *head; // 使用临时指针找到最后一个节点
    while (temp->next != NULL) { // 遍历直到找到最后一个节点
        temp = temp->next;
    }
    temp->next = newNode; // 将最后一个节点的下一个指向新节点
    newNode->prev = temp; // 将新节点的前一个指向最后一个节点
}

// 打印链表
void printList(Node* head) {
    Node* temp = head; // 从头节点开始
    while (temp != NULL) { // 遍历所有节点
        printf("%d -> ", temp->data); // 打印每个节点的数据
        temp = temp->next; // 移动到下一个节点
    }
    printf("NULL\n"); // 在链表末尾打印 NULL
}

int main() {
    Node* head = NULL; // 初始化头节点为 NULL
    insertAtHead(&head, 1); // 在头部插入 1
    insertAtHead(&head, 2); // 在头部插入 2
    insertAtHead(&head, 3); // 在头部插入 3
    printList(head); // 打印链表: 3 -> 2 -> 1 -> NULL
    
    insertAtTail(&head, 4); // 在尾部插入 4
    printList(head); // 打印链表: 3 -> 2 -> 1 -> 4 -> NULL

    return 0;
}