单链表基础操作

1.初始化单链表

  • 将头结点指向空。

2.尾插

  • 空链表,直接插在头结点上
  • 非空链表,找到最后一个结点,指向插入的结点

3.尾删

  • 空链表,直接返回
  • 只有一个结点,直接删除当前头结点,并将head指向空
  • 否则,找到倒数第二个结点,将其指向空

4.头插

  • 空链表,直接插在头结点上
  • 创建新的结点,指向头结点,并更新head指向

5.头删

  • 空链表,直接返回
  • 非空链表,直接将head指针指向下一个

6.查找元素在链表中的位置

  • 遍历链表

7.在pos之前插入元素

  • 对于空链表来说,pos无意义,只能把这个元素作为唯一的节点,并让头结点指针指向这个节点
  • pos若指向头结点,无法找到pos之前结点,处理成头插
  • 找到pos的前一个位置cur,插入;若未找到pos直接返回

8.在pos之后插入元素

  • 对于空链表来说,pos无意义,只能把这个元素作为唯一的节点,并让头结点指针指向这个节点
  • 非空直接插入

9.删除指定位置的元素

  • 空链表,删除失败
  • 要删除的刚好是头结点,修改head指向即可
  • pos指向任何位置,此时需要找到pos的前一个位置,然后进行删除
  • pos在链表上不存在,直接返回

10.删除指定值的元素

  • 空链表,删除失败
  • 非空,找到该元素,删除

11.删除指定值的所有元素

  • 空链表,删除失败
  • 非空,通过循环找到指定值的所以元素,删除

12.判断链表是否为空

  • 为空返回1,否则返回0

13.求链表元素个数

  • 遍历链表,返回元素个数

具体实现代码:
①linklist.h

#pragma once

#include <stddef.h>
#include <stdio.h>

typedef char LinkType;

typedef struct LinkNode{
    LinkType data;
    struct LinkNode* next;
}LinkNode;

void LinkListInit(LinkNode** head);            //初始化

void LinkListPrintChar(LinkNode* head, const char* msg);    //打印链表

LinkNode* LinkListPushBack(LinkNode** head, LinkType value);   //尾插

void LinkListPopBack(LinkNode** head);        //尾删

void LinkListPushFront(LinkNode** head, LinkType value);    //头插

void LinkListPopFront(LinkNode** head);     //头删

LinkNode* LinkListFind(LinkNode* head, LinkType to_find);     //查找元素在链表中的位置

void LinkListInsert(LinkNode** head, LinkNode* pos, LinkType value);       //在pos之前插入元素

void LinkListInsertAfter(LinkNode** head, LinkNode* pos, LinkType value);       //在pos之后插入元素

void LinkListErase1(LinkNode** head, LinkNode* pos);           //删除指定位置的元素

void LinkListErase2(LinkNode** head, LinkNode** pos);

void LinkListRemove1(LinkNode** head, LinkType value);          //删除指定值的元素

void LinkListRemove2(LinkNode** head, LinkType value);         

void LinkListRemoveAll(LinkNode** head, LinkType value);          //删除指定值的所有元素

int LinkListEmpty(LinkNode* head);          //判断链表是否为空,为空返回1,否则返回0

size_t LinkListSize(LinkNode* head);        //求链表元素个数

②linklist.c

#include "linklist.h"

#include <stdlib.h>

void LinkListInit(LinkNode** head)    //初始化
{
    if (head == NULL)    //非法操作
    {
        return;
    }
    *head = NULL;
}

LinkNode* LinkListCreateNode(LinkType value)    //创建结点
{
    LinkNode* ptr = (LinkNode *)malloc(sizeof(LinkNode));
    ptr->data = value;
    ptr->next = NULL;
    return ptr;
}

void LinkListDestroyNode(LinkNode* ptr)         //销毁结点
{
    free(ptr);
}


void LinkListPrintChar(LinkNode* head, const char* msg)    //打印链表
{
    printf("[%s]:", msg);
    LinkNode* cur = head;
    for (; cur != NULL; cur = cur->next)
    {
        printf("[%c:%p] -> ", cur->data, cur);
    }
    printf("[NULL]\n\n");
}


LinkNode* LinkListPushBack(LinkNode** head, LinkType value)   //尾插
{
    if (head == NULL)    //非法输入
    {
        return NULL;
    }
    if (*head == NULL)    //空链表,直接插在头结点上
    {
        *head = LinkListCreateNode(value);
        return *head;
    }
    LinkNode* cur = *head;
    while (cur->next != NULL)
    {
        cur = cur->next;
    }
    cur->next = LinkListCreateNode(value);
    return cur->next;
}

void LinkListPopBack(LinkNode** head)        //尾删
{
    if (head == NULL)
    {
        return;        //非法输入
    }
    if (*head == NULL)
    {
        return;     //空链表,什么也不干
    }
    LinkNode* cur = *head;
    if (cur->next == NULL)
    {
        //只有一个结点,直接删除当前头结点
        LinkListDestroyNode(cur);
        *head = NULL;
        return;
    }
    while (cur->next != NULL)
    {
        if (cur->next->next == NULL)
        {
            //找到倒数第二个结点
            LinkNode* to_delete = cur->next;
            cur->next = NULL;
            LinkListDestroyNode(to_delete);
        }
        else
        {
            cur = cur->next;
        }
    }
    return;
}

void LinkListPushFront(LinkNode** head, LinkType value)   //头插
{
    if (head == NULL)
    {
        return;    //非法输入
    }
    if (*head == NULL)    //空链表,直接插在头结点上
    {
        *head = LinkListCreateNode(value);
        return;
    }
    LinkNode* new_node = LinkListCreateNode(value);
    new_node->next = *head;
    *head = new_node;
    return;
}

void LinkListPopFront(LinkNode** head)     //头删
{
    if (head == NULL)
    {
        return;   //非法输入
    }
    if (*head == NULL)
    {
        return;     //空链表,什么也不干
    }
    LinkNode* to_delete = *head;
    *head = (*head)->next;
    LinkListDestroyNode(to_delete);
}

LinkNode* LinkListFind(LinkNode* head, LinkType to_find)     //查找元素在链表中的位置
{
    LinkNode* cur = head;
    for (; cur != NULL; cur = cur->next)
    {
        if (cur->data == to_find)
        {
            return cur;
        }
    }
    return NULL;
}

void LinkListInsert(LinkNode** head, LinkNode* pos, LinkType value)       //在pos之前插入元素
{
    if (head == NULL)
    {
        return;        //非法输入
    }
    if (*head == NULL)
    {
        //对于空链表来说,pos无意义,只能把这个元素作为唯一的节点,并让头结点指针指向这个节点
        *head = LinkListCreateNode(value);
        return;
    }
    if (*head == pos)
    {
        //pos指向头结点,无法找到pos之前结点,处理成头插
        LinkListPushFront(head, value);
        return;
    }
    if (pos == NULL)
    {
        LinkListPushBack(head, value);
        return;
    }
    LinkNode* cur = *head;
    while(cur->next != NULL)
    {
        if (cur->next == pos)
        {
            //找到pos的前一个位置cur,插入
            LinkNode* new_node = LinkListCreateNode(value);
            new_node->next = pos;
            cur->next = new_node;
            return;
        }
        else
        {
            cur = cur->next;
        }
    }
    //未找到pos,直接返回
    return;
}

void LinkListInsertAfter(LinkNode** head, LinkNode* pos, LinkType value)       //在pos之后插入元素
{
    if (head == NULL)
    {
        return;     //非法输入
    }
    if (*head == NULL)
    {
        //对于空链表来说,pos无意义,只能把这个元素作为唯一的节点,并让头结点指针指向这个节点
        *head = LinkListCreateNode(value);
        return;
    }
    if (pos == NULL)
    {
        return;    //非法输入
    }
    LinkNode* new_node = LinkListCreateNode(value);
    new_node->next = pos->next;
    pos->next = new_node;
}

void LinkListErase1(LinkNode** head, LinkNode* pos)           //删除指定位置的元素
{
    if (head == NULL || pos == NULL)
    {
        return;     //非法输入
    }
    if (*head == NULL)
    {
        return;     //空链表,删除失败
    }
    if (*head == pos)
    {
        //要删除的刚好是头结点,修改head指向即可
        LinkNode* to_delete = *head;
        *head = (*head)->next;
        LinkListDestroyNode(to_delete);
        return;
    }
    //pos指向任何位置,此时需要找到pos的前一个位置
    LinkNode* cur = *head;
    while (cur->next != NULL)
    {
        if (cur->next == pos)
        {
            //进行删除动作
            cur->next = pos->next;
            LinkListDestroyNode(pos);
            return;
        }
        else
        {
            cur = cur->next;
        }
    }
    return;   //pos在链表上不存在
}

void LinkListErase2(LinkNode** head, LinkNode** pos)
{
    if (head == NULL)
    {
        return;    //非法输入
    }
    if (*head == NULL)
    {
        return;    //空链表,删除失败
    }
    if (*pos != NULL && (*pos)->next != NULL)
    {
        (*pos)->data = (*pos)->next->data;
        LinkNode* to_delete = (*pos)->next;
        (*pos)->next = to_delete->next;
        LinkListDestroyNode(to_delete);
        return;
    }
    if ((*pos)->next == NULL)
    {
        LinkNode* to_delete = *pos;
        *pos = NULL;
        LinkListDestroyNode(to_delete);
        return;
    }
}

void LinkListRemove1(LinkNode** head, LinkType value)          //删除指定值的元素
{
    if (head == NULL)
    {
        return;    //非法输入
    }
    if (*head == NULL)
    {
        return;       //空链表,删除失败
    }
    LinkNode* pos = LinkListFind(*head, value);
    LinkListErase1(head, pos);
}

void LinkListRemove2(LinkNode** head, LinkType value)
{
    if (head == NULL)
    {
        return;      //非法输入
    }
    if (*head == NULL)
    {
        return;       //空链表,删除失败
    }
    if ((*head)->data == value)      //要删除的是头结点
    {
        LinkNode* to_delete = *head;
        *head = (*head)->next;
        LinkListDestroyNode(to_delete);
        return;
    }
    LinkNode* pre = *head;
    LinkNode* cur = (*head)->next;
    while (cur != NULL)
    {
        if (cur->data == value)
        {
            pre->next = cur->next;
            LinkListDestroyNode(cur);
            return;
        }
        else
        {
            pre = pre->next;
            cur = cur->next;
        }
    }
    //要删除的元素不存在,直接返回
    return;     
}

void LinkListRemoveAll(LinkNode** head, LinkType value)          //删除指定值的所有元素
{
    if (head == NULL)
    {
        return;    //非法输入
    }
    if (*head == NULL)
    {
        return;     //空链表,删除失败
    }
    while (1)
    {
        LinkNode* pos = LinkListFind(*head, value);
        if (pos == NULL)
        {
            break;
        }
        LinkListErase1(head, pos);
    }
    return;
}

int LinkListEmpty(LinkNode* head)          //判断链表是否为空,为空返回1,否则返回0
{
    return head == NULL ? 1 : 0;
}

size_t LinkListSize(LinkNode* head)        //求链表元素个数
{
    if (head == NULL)
    {
        return 0;    //空链表
    }
    size_t count = 0;
    LinkNode* cur = head;
    while (cur != NULL)
    {
        ++count;
        cur = cur->next;
    }
    return count;
}

③test.c

#include "linklist.h"

#include <windows.h>

#define TEST_HEADER printf("\n========================================%s===========================================\n",__FUNCTION__)

void TestInit()
{
    LinkNode* head;
    LinkListInit(&head);
    printf("head = %p,%ld\n", head,(long)head);
}

void TestPushBack()
{
    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);
    LinkListPushBack(&head, 'a');
    LinkListPushBack(&head, 'b');
    LinkListPushBack(&head, 'c');
    LinkListPushBack(&head, 'd');
    LinkListPrintChar(head, "尾插四个元素");
}

void TestPopBack()
{
    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);
    LinkListPopBack(&head);
    LinkListPrintChar(head, "尝试对空链表尾删");
    LinkListPushBack(&head, 'a');
    LinkListPopBack(&head);
    LinkListPrintChar(head, "尝试对只有一个元素链表尾删");
    LinkListPushBack(&head, 'a');
    LinkListPushBack(&head, 'b');
    LinkListPushBack(&head, 'c');
    LinkListPushBack(&head, 'd');
    LinkListPrintChar(head, "尾插四个元素");
    LinkListPopBack(&head);
    LinkListPopBack(&head);
    LinkListPrintChar(head, "尾删两个个元素");
}

void TestPushFront()
{
    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);
    LinkListPushFront(&head, 'a');
    LinkListPushFront(&head, 'b');
    LinkListPushFront(&head, 'c');
    LinkListPushFront(&head, 'd');
    LinkListPrintChar(head, "头插四个元素");
}

void TestPopFront()
{
    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);
    LinkListPopFront(&head);
    LinkListPrintChar(head, "尝试对空链表头删");
    LinkListPushFront(&head, 'a');
    LinkListPushFront(&head, 'b');
    LinkListPushFront(&head, 'c');
    LinkListPushFront(&head, 'd');
    LinkListPrintChar(head, "头插四个元素");
    LinkListPopFront(&head);
    LinkListPopFront(&head);
    LinkListPrintChar(head, "头删两个元素");
    LinkListPopFront(&head);
    LinkListPopFront(&head);
    LinkListPrintChar(head, "再头删两个元素");
}

void TestFind()
{
    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);
    LinkListPushBack(&head, 'a');
    LinkListPushBack(&head, 'b');
    LinkNode* pos_c = LinkListPushBack(&head, 'c');
    LinkListPushBack(&head, 'd');
    LinkListPrintChar(head, "尾插四个元素");

    LinkNode* pos = LinkListFind(head, 'e');
    printf("[查找e]:pos expect NULL,actual %p\n", pos);

    pos = LinkListFind(head, 'c');
    printf("[查找c]:pos expect %p,actual %p\n", pos_c, pos);
}

void TestInsert()
{
    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);
    LinkListInsert(&head, head, 'b');
    LinkListPrintChar(head, "对空链表插入");

    LinkListInsert(&head, head, 'a');
    LinkListPrintChar(head, "对只有头结点链表插入");

    LinkNode* pos = LinkListPushBack(&head, 'd');
    LinkListPrintChar(head, "尾插一个元素");

    LinkListInsert(&head, pos, 'c');
    LinkListPrintChar(head, "在d之前插入");

    LinkListInsert(&head, NULL, 'e');
    LinkListPrintChar(head, "在链表尾部插入");
}

void TestInsertAfter()
{
    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);
    LinkListInsertAfter(&head, head, 'a');
    LinkListPrintChar(head, "对空链表插入");

    LinkListInsertAfter(&head, head, 'b');
    LinkListPrintChar(head, "对只有头结点链表插入");

    LinkNode* pos = LinkListPushBack(&head, 'c');
    LinkListPrintChar(head, "尾插一个元素");

    LinkListInsertAfter(&head, pos, 'd');
    LinkListPrintChar(head, "在c之后插入");
}

void TestErase1()
{
    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);
    LinkListErase1(&head, NULL);
    LinkListPrintChar(head, "尝试对空链表进行删除");
    LinkListPushBack(&head, 'a');
    LinkListPushBack(&head, 'b');
    LinkNode* pos_c = LinkListPushBack(&head, 'c');
    LinkListPushBack(&head, 'd');
    LinkListPrintChar(head, "尾插四个元素");
    LinkListErase1(&head, pos_c);
    LinkListPrintChar(head, "删除元素c");
}

void TestErase2()
{
    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);
    LinkListErase2(&head, NULL);
    LinkListPrintChar(head, "尝试对空链表进行删除");
    LinkListPushBack(&head, 'a');
    LinkListPushBack(&head, 'b');
    LinkNode* pos_c = LinkListPushBack(&head, 'c');
    LinkListPushBack(&head, 'd');
    LinkListPrintChar(head, "尾插四个元素");
    LinkListErase2(&head, &pos_c);
    LinkListPrintChar(head, "删除元素c");
}

void TestRemove1()
{
    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);
    LinkListPushBack(&head, 'a');
    LinkListPushBack(&head, 'b');
    LinkListPushBack(&head, 'c');
    LinkListPushBack(&head, 'd');
    LinkListPrintChar(head, "尾插四个元素");

    LinkListRemove1(&head, 'e');
    LinkListPrintChar(head, "尝试删除不存在元素e");
    LinkListRemove1(&head, 'c');
    LinkListPrintChar(head, "尝试删除元素c");
}

void TestRemove2()
{
    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);
    LinkListPushBack(&head, 'a');
    LinkListPushBack(&head, 'b');
    LinkListPushBack(&head, 'c');
    LinkListPushBack(&head, 'd');
    LinkListPrintChar(head, "尾插四个元素");

    LinkListRemove2(&head, 'e');
    LinkListPrintChar(head, "尝试删除不存在元素e");
    LinkListRemove2(&head, 'c');
    LinkListPrintChar(head, "尝试删除元素c");
}

void TestRemoveAll()
{
    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);
    LinkListRemoveAll(&head, 'a');
    LinkListPrintChar(head, "尝试对空链表进行删除");

    LinkListPushBack(&head, 'a');
    LinkListPushBack(&head, 'b');
    LinkListPushBack(&head, 'c');
    LinkListPushBack(&head, 'c');
    LinkListPushBack(&head, 'c');
    LinkListPushBack(&head, 'c');
    LinkListPushBack(&head, 'd');
    LinkListPrintChar(head, "尾插七个元素");

    LinkListRemoveAll(&head, 'e');
    LinkListPrintChar(head, "尝试删除不存在元素e");
    LinkListRemoveAll(&head, 'c');
    LinkListPrintChar(head, "尝试删除元素c");
}

void TestEmpty()
{
    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);
    int ret = LinkListEmpty(head);
    printf("ret expect 1,actual %d\n", ret);

    LinkListPushBack(&head, 'a');
    LinkListPushBack(&head, 'b');
    LinkListPushBack(&head, 'c');
    LinkListPushBack(&head, 'd');
    LinkListPrintChar(head, "尾插四个元素");
    ret = LinkListEmpty(head);
    printf("ret expect 0,actual %d\n", ret);
}

void TestSize()
{
    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);
    size_t ret = LinkListSize(head);
    printf("ret expect 0,actual %d\n", ret);

    LinkListPushBack(&head, 'a');
    LinkListPushBack(&head, 'b');
    LinkListPushBack(&head, 'c');
    LinkListPushBack(&head, 'd');
    LinkListPrintChar(head, "尾插四个元素");
    ret = LinkListSize(head);
    printf("ret expect 4,actual %d\n", ret);
}

int main()
{
    TestInit();
    TestPushBack();
    TestPopBack();
    TestPushFront();
    TestPopFront();
    TestFind();
    TestInsert();
    TestInsertAfter();
    TestErase1();
    TestErase2();
    TestRemove1();
    TestRemove2();
    TestRemoveAll();
    TestEmpty();
    TestSize();
    system("pause");
    return 0;
}

结果:
结果

结果

结果

结果

未完待续。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值