数据结构-链表的基本操作

对单向的不带环不带头节点的链表做以下操作:

linklist.h

//单向的不带环不带头节点的链表
#pragma once 

typedef char LinkNodeType;

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


typedef LinkNode* PLinkNode;

void LinkListInit(PLinkNode*);                                //初始化

void LinkListDestroy(PLinkNode*);                             //销毁

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

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

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

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

//将一个元素插入到pos之后
void LinkListInsert(LinkNode* pos,LinkNodeType value);

//将一个元素插入到pos之前
void LinkListInsertBefore(LinkNode** head,LinkNode* pos,LinkNodeType value);

//优化后将元素插入到pos之前
void LinkListInsertBefore2(LinkNode* pos,LinkNodeType value);

//删除元素
void LinkListErase(LinkNode** head,LinkNode* pos);

//优化后的删除
void LinkListErase2(LinkNode** head,LinkNode* pos);

//给一个元素找位置
LinkNode* LinkListFind(LinkNode* head,LinkNodeType to_find);

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

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

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

//删除指定值的所有元素
void LinkListRemoveAll(LinkNode** head,LinkNodeType value);
linklist.c
#include"linklist.h"
#include<stdio.h>
#include<stdlib.h>

LinkNode* CreateNode(LinkNodeType value)//创建节点
{
    LinkNode* new_node =(LinkNode *)malloc(sizeof(LinkNode));
    new_node->data = value;
    new_node->next = NULL;
    return new_node;
}

void DestroyNode(LinkNode* node)//销毁节点
{
    free(node);
}
void LinkListInit(PLinkNode* node)//链表初始化
{
    *node = NULL;
}

void LinkListDestroy(LinkNode** phead)//销毁链表
{
    if(phead == NULL)
        return;          //非法输入

    if(*phead == NULL)
        return;          //空链表

    LinkNode* cur =  *phead;
    while(cur != NULL)
    {
        LinkNode* to_delete = cur;
        cur = cur->next;
        DestroyNode(to_delete);
    }
    *phead = NULL;
}

void LinkListPushBack(LinkNode** phead,LinkNodeType value)//尾插
{
    if(phead == NULL)
        return;         //非法输入

    if(*phead == NULL)
    {
        //空链表
        *phead = CreateNode(value);
        return;
    }
    //链表非空
    LinkNode* cur = *phead;
    while(cur->next != NULL)
    {
        cur = cur->next;
    }
    LinkNode* new_node = CreateNode(value);
    cur->next = new_node;
}

void LinkListPopBack(LinkNode** phead)//尾删
{
    if(phead ==NULL) 
        return;        //非法输入

    if(*phead == NULL)
        return;        //单链表

    if((*phead)->next == NULL)
    {
        //链表只有一个元素
        DestroyNode(*phead);
        *phead = NULL;
        return;
    }
     LinkNode* cur = *phead;
     LinkNode* pre = NULL;
     while(cur->next != NULL)
     {
         pre = cur;
         cur = cur->next;
     }
     pre->next = NULL;
     DestroyNode(cur);
     return;
}

void LinkListPushFront(LinkNode** phead,LinkNodeType value)//头插
{
    if(phead == NULL)
        return;                      //非法输入

    LinkNode* new_node = CreateNode(value);
    new_node->next = *phead;
    *phead = new_node;
}

void LinkListPopFront(LinkNode** phead)//头删
{
    if(phead == NULL)
        return;              //非法输入
    if(*phead == NULL)
        return;              //空链表

    LinkNode* to_erase = *phead;
    *phead = (*phead)->next;
    DestroyNode(to_erase);
    return;
}

void LinkListInsert(LinkNode* pos,LinkNodeType value)//在pos后面插入一个新节点
{
    if(pos == NULL)
        return;            
    //非法输入,pos表示一个节点的指针
    //如果pos为空,说明根本不存再这样的节点
    LinkNode* new_node = CreateNode(value);
    new_node->next = pos->next;
    pos->next = new_node;
    return;
}

void LinkListInsertBefore(LinkNode** phead,LinkNode* pos,LinkNodeType value)//在pos前面插入一个新节点
{
    if(phead == NULL ||pos == NULL)
        return;                 //非法输入

    if(pos == *phead)
    {
        //要插的地方刚好是头节点
        LinkListPushFront(phead,value);
        return;
    }
    LinkNode* cur = *phead;
    for( ;cur != NULL;cur = cur->next)
    {
        if(cur->next == pos)
        {
            break;          //跳出循环时cur刚好是pos的前一个节点
        }
    }
    if(cur == NULL)
    {
        return;
    }
    LinkListInsert(cur,value);
}

//我们可以看到在pos前面插入新节点时,需要遍历链表,找到它的前一个节点,这种算法时间复杂度为O(n);
//而下面这种算法,通过交换pos位置和新插入节点的数据的方法可以达到同样的目的,时间复杂度为O(1).

void LinkListInsertBefore2(LinkNode* pos,LinkNodeType value)
{
    if(pos == NULL)
    {
        return;            //非法输入
    }
    LinkListInsert(pos,pos->data);
    pos->data = value;
    //交换新插入的节点和pos的位置
}

void LinkListErase(LinkNode** phead,LinkNode* pos)//删除
{
    if((phead == NULL)||(pos == NULL))
       return;       //非法输入

    if(*phead == NULL)
       return;      //空链表

    if(*phead == pos)
        LinkListPopFront(phead);//如果pos是起始位置,调用头删

    LinkNode* cur = *phead;
    for( ;cur != NULL;cur = cur->next)
    {
         if(cur->next == pos)
         {
            cur->next = pos->next;
            pos->next = NULL;
            DestroyNode(pos);
         }
    }
     return;
}

//删除pos位置时,需要遍历链表,找到它的前一个节点,这种算法时间复杂度为O(n);
//而下面这种算法,将pos->next的数据赋给pos然后删除pos->next节点的方法可以达到同样的目的,时间复杂度为O(1).

void LinkListErase2(LinkNode** phead,LinkNode* pos)
{

    if((phead == NULL)||(pos == NULL))
       return;       //非法输入

    if(*phead == NULL)
       return;      //空链表

    pos->data = pos->next->data;
    LinkNode* to_erase = pos->next;
    pos->next = to_erase->next;
    DestroyNode(to_erase);
    return;
}

LinkNode* LinkListFind(LinkNode* phead,LinkNodeType to_find)//找指定元素的位置
{
    if(phead == NULL)
        return NULL;            //空链表

    LinkNode* cur = phead;
    while(cur != NULL)
    {
        if(cur->data == to_find)
        {
            return cur;
        }
        cur = cur->next;
    }
    return NULL;
}

int  LinkListEmpty(LinkNode* phead)//判断链表是否为空
{
    if(phead == NULL)
    {   
        return 1;           //空链表
    }
    else
    {
        return 0;
    }
}

int LinkListSize(LinkNode* phead)//求链表大小
{
    if(phead == NULL)
        return;             //空链表

    LinkNode* cur = phead;
    size_t count = 0;
    for( ;cur != NULL;cur = cur->next)
    {
         count++;
    }
    return count;
}

void LinkListRemove(LinkNode** phead,LinkNodeType value)//移除指定值的元素
{
    if(phead == NULL)
        return;            //非法输入

    if(*phead == NULL)
        return;            //空链表

    LinkNode* cur = LinkListFind(*phead,value);
    if(cur == NULL)
    {
        return;      //没找到
    }
    LinkListErase(phead,cur);
}

void LinkListRemoveAll(LinkNode** phead,LinkNodeType value)//移除指定值的所有元素
{

    if(phead == NULL)
       return;            //非法输入

    if(*phead == NULL)
       return;            //空链表

    while(1)
    {
            LinkNode* cur = LinkListFind(*phead,value);
            if(cur == NULL)
            {
                 return;
            }
            LinkListErase(phead,cur);
    }
}
///
//以下是测试代码
///

#include<stdio.h>
#define TEST_HEADER printf("\n=====================%s====================\n",__FUNCTION__)

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

}

void TestInit()
{
    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&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');
    LinkListPopBack(&head);
    LinkListPopBack(&head);
    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 TestInsert()
{

    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);
    LinkListPushBack(&head,'a');
    LinkListPushBack(&head,'b');
    LinkListPushBack(&head,'c');
    LinkListPushBack(&head,'d');

    LinkNode* pos = head->next;
    LinkListInsert(pos,'x');
    LinkListPrintChar(head,"插入'x'元素");
}

void TestInsertBefore()
{

    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);
    LinkListPushBack(&head,'a');
    LinkListPushBack(&head,'b');
    LinkListPushBack(&head,'c');
    LinkListPushBack(&head,'d');

    LinkNode* pos1 = head;
    LinkListInsertBefore(&head,pos1,'x');
    LinkListPrintChar(head,"向头节点之前插入'x'元素");

    LinkNode* pos2 = head->next->next;
    LinkListInsertBefore(&head,pos2,'y');
    LinkListPrintChar(head,"向'b'之前插入'y'元素");
}

void TestInsertBefore2()
{

    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);
    LinkListPushBack(&head,'a');
    LinkListPushBack(&head,'b');
    LinkListPushBack(&head,'c');
    LinkListPushBack(&head,'d');

    LinkNode* pos1 = head;
    LinkListInsertBefore(&head,pos1,'x');
    LinkListPrintChar(head,"向头节点之前插入'x'元素");

    LinkNode* pos2 = head->next->next;
    LinkListInsertBefore(&head,pos2,'y');
    LinkListPrintChar(head,"向'b'之前插入'y'元素");
}

void TestErase()
{

    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);

    LinkListErase(&head,(LinkNode*)0x11);
    LinkListPrintChar(head,"尝试对空链表删除");

    LinkListPushBack(&head,'a');
    LinkListPushBack(&head,'b');
    LinkListPushBack(&head,'c');
    LinkListPushBack(&head,'d');

    LinkNode* pos= head;
    LinkListErase(&head,pos);
    LinkListPrintChar(head,"删除元素'a'");

    LinkNode* pos2 = (LinkNode*)0x10;
    LinkListErase(&head,pos2);
    LinkListPrintChar(head,"尝试对一个不存在的位置删除");
}

void TestErase2()
{

    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);

    LinkListErase(&head,(LinkNode*)0x11);
    LinkListPrintChar(head,"尝试对空链表删除");

    LinkListPushBack(&head,'a');
    LinkListPushBack(&head,'b');
    LinkListPushBack(&head,'c');
    LinkListPushBack(&head,'d');

    LinkNode* pos = head->next;
    LinkListErase(&head,pos);
    LinkListPrintChar(head,"删除元素'b'");

    LinkNode* pos2 = (LinkNode*)0x10;
    LinkListErase(&head,pos2);
    LinkListPrintChar(head,"尝试对一个不存在的位置删除");
}

void TestFind()
{

    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);

    LinkNode* pos =  LinkListFind(head,'a');
    printf("'a'的地址是:%p\n",pos);

    LinkListPushBack(&head,'a');
    LinkListPushBack(&head,'b');
    LinkListPushBack(&head,'c');
    LinkListPushBack(&head,'d');

    LinkNode* pos1 =  LinkListFind(head,'c');
    printf("'c'的地址是:%p\n",pos1);

    LinkNode* pos2 =  LinkListFind(head,'x');
    printf("'x'的地址是:%p",pos2);
}

void TestEmpty()
{

    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);

    size_t cur1 = LinkListEmpty(head);
    printf("%d\n",cur1);

    LinkListPushBack(&head,'a');
    LinkListPushBack(&head,'b');
    LinkListPushBack(&head,'c');
    LinkListPushBack(&head,'d');

    size_t cur2 = LinkListEmpty(head);
    printf("%d",cur2);
}

void TestSize()
{
    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);

    size_t cur1 = LinkListSize(head);
    printf("%d\n",cur1);

    LinkListPushBack(&head,'a');
    LinkListPushBack(&head,'b');
    LinkListPushBack(&head,'c');
    LinkListPushBack(&head,'d');

    size_t cur2 = LinkListSize(head);
    printf("%d",cur2);
}

void TestRemove()
{
    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);

    LinkListRemove(&head,'a');
    LinkListPrintChar(head,"尝试对空链表删除");

    LinkListPushBack(&head,'a');
    LinkListPushBack(&head,'b');
    LinkListPushBack(&head,'c');
    LinkListPushBack(&head,'d');

    LinkListRemove(&head,'a');
    LinkListPrintChar(head,"删除元素'a'");

    LinkListRemove(&head,'x');
    LinkListPrintChar(head,"尝试删除一个不存在的值");
}
void TestRemoveAll()
{
    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);

    LinkListRemoveAll(&head,'a');
    LinkListPrintChar(head,"尝试对空链表删除");

    LinkListPushBack(&head,'a');
    LinkListPushBack(&head,'b');
    LinkListPushBack(&head,'a');
    LinkListPushBack(&head,'c');
    LinkListPushBack(&head,'a');
    LinkListPushBack(&head,'d');
    LinkListPushBack(&head,'a');

    LinkListRemoveAll(&head,'a');
    LinkListPrintChar(head,"删除元素'a'");

    LinkListRemoveAll(&head,'x');
    LinkListPrintChar(head,"尝试删除一个不存在的值");
}
int main()
{
    TestInit();
    TestPushBack();
    TestPopBack();
    TestPushFront();
    TestPopFront();
    TestInsert();
    TestInsertBefore();
    TestInsertBefore2();
    TestErase();
    TestErase2();
    TestFind();
    TestEmpty();
    TestSize();
    TestRemove();
    TestRemoveAll();
    printf("\n");
    return 0;
}

注意:对链表操作时要看传入的是一级指针还是二级指针,修改头指针的指向用二级指针,其他用一级指针。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值