1. 链表分类

区分链表的种类可以从三个方向,是否有头节点、是否是单链表和是否循环。

根据这三个属性可以把链表分为2^3 = 8种。其中无头不循环单链表和有头循环双向链表最常用。

2. 头节点对于链表的作用

根据做题的经验,单链表带头通常可以免去额外判断要处理的节点是头节点的情况。

3.LinkedList.h

#define _CRT_SECURE_NO_WARNINGS

// -------- 无头不循环单向链表 -----------

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

typedef int LDataType;

typedef struct LinkedListNode {
    LDataType val;
    struct LinkedListNode* next;
} Node;

typedef struct LinkedList {
    Node* head;
} LinkedList;

// 链表初始化
void LinkedListInit(LinkedList* pLS);

// 链表销毁
void LinkedListDestroy(LinkedList* pLS);

// 根据指定的值创建一个链表节点
Node* CreateNode(LDataType val);

// 头插
void LinkedListPushFront(LinkedList* pLS, LDataType val);

// 头删
void LinkedListPopFront(LinkedList* pLS);

// 尾插
void LinkedListPushBack(LinkedList* pLS, LDataType val);

// 尾删
void LinkedListPopBack(LinkedList* pLS);

// 根据给定val查找链表中的节点,查找成功返回节点地址,失败返回NULL
Node* LinkedListFind(LinkedList* pLS, LDataType val);

// 在pos节点后面插入一个值为val的新节点
void LinkedListInsert(Node* pos, LDataType val);

// 删除值为val的节点,如果没有则什么都不干
void LinkedListDelete(LinkedList* pLS, LDataType val);

// 打印全部链表节点
void LinkedListPrint(LinkedList* pLS);

void Test();

4. LinkedList.c

#include "LinkedList.h"

void LinkedListInit(LinkedList* pLS) {
    assert(pLS != NULL);

    pLS->head = NULL;
}

void LinkedListDestroy(LinkedList* pLS) {
    assert(pLS != NULL);

    Node* curr = pLS->head;
    Node* tmp = NULL;

    while (curr != NULL) {
        tmp = curr;
        curr = curr->next;
        free(tmp);
    }

    pLS->head = NULL;
}

Node* CreateNode(LDataType val) {
    Node* res = (Node *)malloc(sizeof(Node));
    if (res == NULL) {
        assert(0);
        return NULL;
    }

    res->val = val;
    res->next = NULL;

    return res;
}

void LinkedListPushFront(LinkedList* pLS, LDataType val) {
    assert(pLS != NULL);

    Node* newNode = CreateNode(val);
    newNode->next = pLS->head;
    pLS->head = newNode;
}

void LinkedListPopFront(LinkedList* pLS) {
    assert(pLS != NULL);

    // 如果是空链表
    if (pLS->head == NULL) {
        return;
    }

    // 普通链表
    Node* tmp = pLS->head;
    pLS->head = pLS->head->next;
    free(tmp);
}

void LinkedListPushBack(LinkedList* pLS, LDataType val) {
    assert(pLS != NULL);

    Node* newNode = CreateNode(val);

    // 如果是空链表
    if (pLS->head == NULL) {
        pLS->head = newNode;
        return;
    }

    // 普通链表
    Node* curr = pLS->head;
    while (curr->next != NULL) {
        curr = curr->next;
    }
    curr->next = newNode;
}

void LinkedListPopBack(LinkedList* pLS) {
    assert(pLS != NULL);

    // 如果是空链表
    if (pLS->head == NULL) {
        return;
    }

    // 普通链表
    Node* dummyHead = CreateNode(0);
    dummyHead->next = pLS->head;
    Node* curr = dummyHead;

    while (curr->next->next != NULL) {  // 寻找链表倒数第二个元素
        curr = curr->next;
    }

    Node* tmp = curr->next;
    curr->next = curr->next->next;
    free(tmp);

    pLS->head = dummyHead->next;
}

Node* LinkedListFind(LinkedList* pLS, LDataType val) {
    assert(pLS != NULL);

    Node* curr = pLS->head;
    while (curr != NULL) {
        if (curr->val == val) {
            return curr;
        }
        curr = curr->next;
    }

    return NULL;
}

void LinkedListInsert(Node* pos, LDataType val) {
    assert(pos != NULL);

    Node* newNode = CreateNode(val);
    newNode->next = pos->next;
    pos->next = newNode;
}

void LinkedListDelete(LinkedList* pLS, LDataType val) {
    assert(pLS != NULL);

    // 空链表
    if (pLS->head == NULL) {
        return;
    }

    Node* dummyHead = CreateNode(0);
    dummyHead->next = pLS->head;
    Node* curr = dummyHead;

    while (curr->next != NULL && curr->next->val != val) {
        curr = curr->next;
    }

    if (curr->next != NULL) {
        Node* tmp = curr->next;
        curr->next = curr->next->next;
        free(tmp);
    }

    pLS->head = dummyHead->next;
}

void LinkedListPrint(LinkedList* pLS) {
    assert(pLS != NULL);

    Node* curr = pLS->head;
    while (curr != NULL) {
        printf("%d -> ", curr->val);
        curr = curr->next;
    }
    printf("NULL\n");
}

void Test() {
    LinkedList ls;
    LinkedListInit(&ls);

    LinkedListPushFront(&ls, 1);
    LinkedListPushFront(&ls, 2);
    LinkedListPushFront(&ls, 3);
    LinkedListPushFront(&ls, 4);
    LinkedListPushFront(&ls, 5);
    LinkedListPrint(&ls);

    LinkedListPopFront(&ls);
    LinkedListPopFront(&ls);
    LinkedListPrint(&ls);

    LinkedListPushBack(&ls, 0);
    LinkedListPushBack(&ls, -1);
    LinkedListPrint(&ls);

    LinkedListPopBack(&ls);
    LinkedListPrint(&ls);

    Node* res = LinkedListFind(&ls, 3);
    if(res)
        printf("%d\n", res->val);

    LinkedListDelete(&ls, 3);
    LinkedListPrint(&ls);
}

5. main.c

#include "LinkedList.h"

int main() {
    Test();

    system("pause");
    return 0;
}
Last modification:November 10th, 2019 at 10:07 am