单链表的构建、遍历、带头结点与不带头结点的插入

/**
 * @author shuang
 * @for kun
 */

#include "stdio.h"
#include "stdlib.h"
#include "stdbool.h"

typedef int ElemType;

typedef struct LNode {
    ElemType val;
    struct LNode *next;
} LNode, *LinkList;

void construct_link_list(LinkList *list, bool with_head, int range);

void traverse_link_list(LinkList *list);

bool insert_with_head(LinkList *list, int index, ElemType val);

bool insert_without_head(LinkList *list, int index, ElemType val);

int main() {
    LinkList list_with_head, list_without_head;
    construct_link_list(&list_with_head, 1, 10);
    construct_link_list(&list_without_head, 0, 10);
    traverse_link_list(&list_with_head);
    traverse_link_list(&list_without_head);
    putchar(10); // 输出换行符
    insert_with_head(&list_with_head, 1, 10);
    insert_without_head(&list_without_head, 1, 10);
    traverse_link_list(&list_with_head);
    traverse_link_list(&list_without_head);

    return 0;
}

/**
 * 构建一个单链表
 * @param list 链表指针, 传入时应为NULL, 此处为C的引用方式, 即指针的指针, 要调用的时候前面加*即可取值
 * @param with_head 创建的链表是否要带头结点
 */
void construct_link_list(LinkList *list, bool with_head, int range) { // 构建一个单链表
    LinkList val_start_node, val_end_node, node;

    node = (LinkList) malloc(sizeof(LNode));
    node->val = 0;
    val_start_node = node;
    val_end_node = node;
    for (int i = 1; i < range; i++) {
        node = (LinkList) malloc(sizeof(LNode));
        node->val = i;
        node->next = NULL;
        val_end_node->next = node;
        val_end_node = node;
    }

    if (with_head) {
        LinkList head = (LinkList) malloc(sizeof(LNode));
        head->val = -1;
        *list = head;
        head->next = val_start_node;
    } else {
        *list = val_start_node;
    }

}

/**
 * 遍历单链表并依次输出结点值
 * @param list 链表指针, 此处为C的引用方式, 即指针的指针, 要调用的时候前面加*即可取值
 */
void traverse_link_list(LinkList *list) {
    LinkList iter = *list;
    while (iter != NULL) {
        if (iter->val == -1) {
            iter = iter->next;
            continue;
        }
        printf("%d ", iter->val);
        iter = iter->next;
    }
    putchar(10);
}

/**
 * 向带头结点的单链表中插入一个新的结点
 * @param list 链表指针, 此处为C的引用方式, 即指针的指针, 要调用的时候前面加*即可取值
 * @param index 要插入的结点最终在链表中的位置, 以1为起始
 * @param val 要插入的结点的值
 * @return 插入是否成功
 */
bool insert_with_head(LinkList *list, int index, ElemType val) {
    if (*list == NULL) { // 没有头结点不能插入
        return false;
    }
    LinkList iter = *list; // iter: 迭代器, 用来遍历链表的指针
    int j = 0;
    while (iter != NULL && j < index - 1) { // 找到第i-1个结点, 即j = i-1时iter指向的结点
        iter = iter->next;
        j++;
    }
    if (iter == NULL) { // 链表长度不足index - 1
        return false;
    }
    LinkList node = (LinkList) malloc(sizeof(LNode));
    node->val = val;
    node->next = iter->next; // 先给新结点设置尾指针, 否则覆盖iter的尾指针后会丢失
    iter->next = node;
    return true;
}

/**
 * 向不带头结点的单链表中插入一个新的结点
 * @param list 链表指针, 此处为C的引用方式, 即指针的指针, 要调用的时候前面加*即可取值
 * @param index 要插入的结点最终在链表中的位置, 以1为起始
 * @param val 要插入的结点的值
 * @return 插入是否成功
 */
bool insert_without_head(LinkList *list, int index, ElemType val) {
    if (index == 1) { // 直接向头指针后插入的情况
        LinkList node = (LinkList) malloc(sizeof(LNode));
        node->val = val;
        node->next = *list;
        *list = node;
        return true;
    }

    LinkList iter = *list; // iter: 迭代器, 用来遍历链表的指针
    int j = 1;
    while (iter != NULL && j < index - 1) { // 找到第i-1个结点, 即j = i-1时iter指向的结点
        iter = iter->next;
        j++;
    }
    if (iter == NULL) { // 链表长度不足index - 1
        return false;
    }
    LinkList node = (LinkList) malloc(sizeof(LNode)); // 先给新结点设置尾指针, 否则覆盖iter的尾指针后会丢失
    node->val = val;
    node->next = iter->next;
    iter->next = node;
    return true;
}

/**
 * 执行结果
 * 0 1 2 3 4 5 6 7 8 9
 * 0 1 2 3 4 5 6 7 8 9
 *
 * 10 0 1 2 3 4 5 6 7 8 9
 * 10 0 1 2 3 4 5 6 7 8 9
 */
上一篇:单链表的插入法


下一篇:循环单链表(C语言实现)