返回

双向链表与双向循环链表揭秘:数据结构中的关键结构

见解分享

双向链表与单链表的异同

在单链表中,每个节点只包含一个指向直接后继节点的指针,而在双向链表中,每个节点包含两个指针,分别指向直接前驱节点和直接后继节点。这种结构上的差异导致了双向链表具有以下几个优点:

  • 高效的查找操作: 在单链表中,查找一个指定节点需要从链表头开始逐个遍历,而双向链表支持从任意节点开始向前或向后查找,显著提高了查找效率。
  • 方便的插入和删除操作: 在单链表中,插入或删除一个节点需要更新其前驱节点的指针,而在双向链表中,只需要更新其前驱节点和后继节点的指针即可,简化了操作。
  • 支持循环遍历: 双向链表可以形成一个闭合的环,方便地进行循环遍历,而单链表则不能。

双向循环链表的独特性

双向循环链表是在双向链表的基础上进一步改进而成的,其特点是最后一个节点的下一个节点指向链表头节点,链表头节点的上一个节点指向链表尾节点,形成一个闭合的环。这种结构上的优势使其具有以下特性:

  • 高效的循环遍历: 双向循环链表支持从任意节点开始循环遍历,无需考虑边界条件,大大简化了遍历操作。
  • 插入和删除操作的便捷性: 双向循环链表中,插入或删除一个节点只需要更新其相邻节点的指针即可,操作更加便捷。

C语言代码实现

为了更好地理解双向链表和双向循环链表,我们使用C语言对其核心功能进行了实现,具体代码如下:

// 双向链表节点结构体
struct node {
    int data;
    struct node *prev;
    struct node *next;
};

// 初始化双向链表
struct node *init_list() {
    struct node *head = NULL;
    return head;
}

// 在双向链表尾部插入一个节点
void insert_node(struct node **head, int data) {
    struct node *new_node = (struct node *)malloc(sizeof(struct node));
    new_node->data = data;
    new_node->prev = NULL;
    new_node->next = NULL;

    if (*head == NULL) {
        *head = new_node;
    } else {
        struct node *current = *head;
        while (current->next != NULL) {
            current = current->next;
        }
        current->next = new_node;
        new_node->prev = current;
    }
}

// 删除双向链表中的一个节点
void delete_node(struct node **head, int data) {
    struct node *current = *head;

    while (current != NULL) {
        if (current->data == data) {
            if (current == *head) {
                *head = current->next;
            } else {
                current->prev->next = current->next;
            }

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

            free(current);
            break;
        }
        current = current->next;
    }
}

// 查找双向链表中的一个节点
struct node *search_node(struct node *head, int data) {
    struct node *current = head;

    while (current != NULL) {
        if (current->data == data) {
            return current;
        }
        current = current->next;
    }

    return NULL;
}

// 打印双向链表
void print_list(struct node *head) {
    struct node *current = head;

    while (current != NULL) {
        printf("%d ", current->data);
        current = current->next;
    }
    printf("\n");
}

// 双向循环链表节点结构体
struct cnode {
    int data;
    struct cnode *prev;
    struct cnode *next;
};

// 初始化双向循环链表
struct cnode *init_clist() {
    struct cnode *head = NULL;
    return head;
}

// 在双向循环链表尾部插入一个节点
void insert_cnode(struct cnode **head, int data) {
    struct cnode *new_node = (struct cnode *)malloc(sizeof(struct cnode));
    new_node->data = data;
    new_node->prev = NULL;
    new_node->next = NULL;

    if (*head == NULL) {
        *head = new_node;
        new_node->next = new_node;
        new_node->prev = new_node;
    } else {
        struct cnode *current = *head;
        while (current->next != *head) {
            current = current->next;
        }
        current->next = new_node;
        new_node->prev = current;
        new_node->next = *head;
        (*head)->prev = new_node;
    }
}

// 删除双向循环链表中的一个节点
void delete_cnode(struct cnode **head, int data) {
    struct cnode *current = *head;

    while (current != NULL) {
        if (current->data == data) {
            if (current == *head) {
                *head = current->next;
            } else {
                current->prev->next = current->next;
            }

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

            free(current);
            break;
        }
        current = current->next;
    }
}

// 查找双向循环链表中的一个节点
struct cnode *search_cnode(struct cnode *head, int data) {
    struct cnode *current = head;

    while (current != NULL) {
        if (current->data == data) {
            return current;
        }
        current = current->next;
    }

    return NULL;
}

// 打印双向循环链表
void print_clist(struct cnode *head) {
    struct cnode *current = head;

    while (current != NULL) {
        printf("%d ", current->data);
        current = current->next;
        if (current == head) {
            break;
        }
    }
    printf("\n");
}

int main() {
    // 创建双向链表
    struct node *head = init_list();

    // 插入一些节点
    insert_node(&head, 1);
    insert_node(&head, 2);
    insert_node(&head, 3);
    insert_node(&head, 4);

    // 打印双向链表
    printf("双向链表:");
    print_list(head);

    // 删除一个节点
    delete_node(&head, 2);

    // 查找一个节点
    struct node *found_node = search_node(head, 3);
    if (found_node != NULL) {
        printf("找到节点:%d\n", found_node->data);
    } else {
        printf("未找到节点\n");
    }

    // 创建双向循环链表
    struct cnode *chead = init_clist();

    // 插入一些节点
    insert_cnode(&chead, 1);
    insert_cnode(&chead, 2);
    insert_cnode(&chead, 3);
    insert_cnode(&chead, 4);

    // 打印双向循环链表
    printf("双向循环链表:");
    print_clist(chead);

    // 删除一个节点
    delete_cnode(&chead, 2);

    // 查找一个节点
    struct cnode *found_cnode = search_cnode(chead, 3);
    if (found_cnode != NULL) {
        printf("找到节点:%d\n", found_cnode->data);
    } else {
        printf("未找到节点\n");
    }

    return 0;
}

总结

双向链表和双向循环链表在数据结构中占有重要地位,它们具有高效查找、