c语言实现单链表的基础操作

接下来将介绍c语言实现单链表的一些基础操作:

 1. 初始化单链表
 2. 创建链表的节点
 3. 打印链表
 4. 销毁链表
 5. 尾部插入链表
 6. 尾部删除链表
 7. 头部插入元素
 8. 尾部插入元素
 9. 指定位置前插入元素
 10. 指定位置后插入元素
 11. 删除元素
 12. 删除指定元素
 13. 删除所有相同元素
 14. 判断链表是否为空
 15. 求链表长度

具体的实现代码如下:

头文件:linklist.h

#pragma once

//#include<stddef.h>

#define TestType printf("\n*************************%s*****************************\n",__FUNCTION__);

typedef char LinkNodeType;

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


void LinkListInit(LinkNode** node);

LinkNode* CreateNode(LinkNodeType value);


void LinkListPrintChar(LinkNode* phead,const char* msg);

void LinkListDestroy(LinkNode** phead);

void LinkListPushBack(LinkNode** phead, LinkNodeType value);

void LinkListPopBack(LinkNode** phead);

void LinkListPushFront(LinkNode** phead,LinkNodeType value);

void LinkListPopFront(LinkNode** phead);

LinkNode* LinkListFind(LinkNode* phead,LinkNodeType to_find);

void LinkListInsert(LinkNode** phead,LinkNode* pos,LinkNodeType value);

void LinkListInsertAfter(LinkNode** phead,LinkNode* pos,LinkNodeType value);

void LinkListErase1(LinkNode** phead,LinkNode* pos);

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

void LinkListRemove(LinkNode** phead,LinkNodeType value);

void LinkListRemoveAll(LinkNode** phead,LinkNodeType value);

int LinkListEmpty(LinkNode* phead);

size_t LinkListSize(LinkNode* phead);

实现函数: linklist.c

#include"linklist.h"
#include<stdlib.h>
#include<stdio.h>

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

}

//初始化链表,将头指针指向空
void LinkListInit(LinkNode** node){
    if(node == NULL){
        //非法输入
        return;
    }
    *node = NULL;
}

//构造新的节点
LinkNode* CreateNode(LinkNodeType value){
    LinkNode* new_node = (LinkNode*)malloc(sizeof(LinkNode));
    if(new_node == NULL){
        printf("申请内存失败!\n");
        exit(1);
    }else{
        new_node->data = value;
        new_node->next = NULL;
        return new_node;
    }
}

//释放节点
void DestroyNode(LinkNode* node){
    free(node);
}

//销毁链表
void LinkListDestroy(LinkNode** phead){
    if(phead == NULL){
        return;
    }
    if(*phead == NULL){
        return;
    }
    //遍历整个链表,从头开始删除
    while((*phead)->next != NULL){
        LinkNode* pnode = *phead;
        *phead = (*phead)->next;
        free(pnode);
        pnode = NULL;
    }
    return;
}

//尾部插入元素
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;
    }
    //找到最后一个节点的指针
    cur->next = CreateNode(value);
    return;
}

//尾部删除
void LinkListPopBack(LinkNode** phead){

    if(phead == NULL){
        return;
    }

    if(*phead == NULL){
        printf("链表为空,无法删除.\n");
        return;
    }

    if((*phead)->next == NULL){
        DestroyNode(*phead);
        *phead = NULL;
        return;
    }

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

//头部插入节点
void LinkListPushFront(LinkNode** phead,LinkNodeType value){
    if(phead == NULL){
        return;
    }
    if(*phead == NULL){
        *phead = CreateNode(value);
        return;
    }
    LinkNode* cur = *phead;
    *phead = CreateNode(value);
    (*phead)->next = cur;
    return;
}

//头部删除节点
void LinkListPopFront(LinkNode** phead){
    if(phead == NULL){
        return;
    }
    if(*phead == NULL){
        printf("链表为空,无法删除.\n");
        return;
    }
    LinkNode* cur = (*phead)->next;
    (*phead)->next = NULL;
    DestroyNode(*phead);
    *phead = cur;
    return;
}

//查找节点
LinkNode* LinkListFind(LinkNode* phead,LinkNodeType to_find){
    if(phead == NULL){
        printf("链表为空,查找不到!\n");
        return;
    }
    LinkNode* cur = phead;
    for(;cur != NULL; cur = cur->next){
        if(cur->data == to_find){
            return cur;
        }
    }
    return;
}

//指定位置前插入节点
void LinkListInsert(LinkNode** phead,LinkNode* pos,LinkNodeType value){
    if(phead == NULL){
        return;
    }
    if(*phead == NULL){
        //若为空链表,pos位置无效,将value当作新节点插入
        *phead = CreateNode(value);
        return;
    }
    if(pos == NULL){
        //pos为NULL,简化为尾插
        LinkListPushBack(phead,value);
        return;
    }
    if(pos == *phead){
        //pos为头节点,简化为头插
        LinkListPushFront(phead,value);
        return;
    }
    LinkNode* cur = *phead;
    while(cur->next != NULL){
        if(cur->next == pos){
            LinkNode* tmp = CreateNode(value);
            tmp->next = pos;
            cur->next = tmp;
            return;
        }
        cur = cur->next;
    }
    printf("没有找到!\n");
    return;
}

//指定位置后插入节点
void LinkListInsertAfter(LinkNode** phead,LinkNode* pos,LinkNodeType value){
    if(phead == NULL){
        return;
    }
    if(*phead == NULL){
        //链表为空,则直接将value作为新节点插入
        *phead = CreateNode(value);
        return;
    }
    if(pos == NULL){
        printf("[ pos = NULL ]\n");
        printf("非法输入!\n\n");
        return;
    }
    LinkNode* cur = *phead;
    while(cur->next != NULL){
        if(cur == pos){
            LinkNode* tmp = CreateNode(value);
            tmp->next = cur->next;
            cur->next = tmp;
            return;
        }
        cur = cur->next;
    }
    return;
}

void LinkListErase1(LinkNode** phead,LinkNode* pos){
    //找到前一个元素进行删除的方法
    if(phead == NULL || pos == NULL){
        //非法输入
        return;
    }
    if(*phead == NULL){
        printf("[ phead = NULL ]\n");
        printf("空链表,无法删除!\n\n");
        return;
    }
    if(*phead == pos){
        //删除位置是头节点
        LinkNode* to_delete = *phead;
        *phead = (*phead)->next;
        DestroyNode(to_delete);
        to_delete->next = NULL;
        return;
    }

    //找到前一个节点进行删除
    LinkNode* cur = *phead;
    while(cur != NULL){
        if(cur->next == pos){
            cur->next = pos->next;
            DestroyNode(pos);
            pos->next = NULL;
            return;
        }
        cur = cur->next;
    }
    return;
}

//移形换位法,用要删除节点的后一个节点覆盖前一个节点,删除后面的节点
//优点:不用遍历整合链表
void LinkListErase2(LinkNode** phead,LinkNode** pos){
    if(phead == NULL){
        return;
    }
    if(*phead == NULL){
        printf("[ phead = NULL ]\n");
        printf("链表为空,无法删除!\n\n");
        return;
    }
    if(*pos != NULL && (*pos)->next != NULL){
        LinkNode* to_delete = (*pos)->next;
        (*pos)->data = to_delete->data;
        (*pos)->next = to_delete->next;
        to_delete->next = NULL;
        DestroyNode(to_delete);
        return;
    }
    if((*pos)->next == NULL){
        LinkListPopBack(phead);
        return;
    }
    printf(" 找不到pos,无法删除!\n");
    return;
}

//删除指定的节点
void LinkListRemove(LinkNode** phead,LinkNodeType value){
    if(phead == NULL){
        return;
    }
    if(*phead == NULL){
        return;
    }
    LinkNode* pos = LinkListFind(*phead,value);
    LinkListErase1(phead,pos);
}

//删除链表中所有指定的元素
void LinkListRemoveAll(LinkNode** phead,LinkNodeType value){
    if(phead == NULL){
        return;
    }
    if(*phead == NULL){
        return;
    }
    while(1){
        LinkNode* to_delete = LinkListFind(*phead,value);
        if(to_delete == NULL){
            break;
        }
        LinkListErase1(phead,to_delete);
    }
    return;
}

//判断链表是否为空,为空返回1 不为空返回0
int LinkListEmpty(LinkNode* phead){

    return phead == NULL ? 1 : 0;

}

//求链表的长度
size_t LinkListSize(LinkNode* phead){
    size_t  count = 1;
    if(phead == NULL){
        return 0;
    }
    LinkNode* cur = phead;
    for(;cur->next != NULL;cur = cur->next){
        count++;
    }
    return count;
}

测试函数:main.c

#include"linklist.h"
#include<stdio.h>

void TestInit(){
    TestType;
    LinkNode* phead;
    LinkListInit(&phead);
    printf("phead = %p\n",phead);
}


void TestPushBack(){
    TestType;
    LinkNode* phead;
    LinkListInit(&phead);
    LinkListPushBack(&phead,'a');
    LinkListPushBack(&phead,'b');
    LinkListPushBack(&phead,'c');
    LinkListPushBack(&phead,'d');
    LinkListPrintChar(phead," 尾部插入");
    LinkListPopBack(&phead);
    LinkListPrintChar(phead," 尾部删除 ");
}

void TestLinkListPushFront(){
    TestType;
    LinkNode* phead;
    LinkListInit(&phead);
    LinkListPushBack(&phead,'a');
    LinkListPushBack(&phead,'b');
    LinkListPushBack(&phead,'c');
    LinkListPushBack(&phead,'d');
    LinkListPrintChar(phead," 尾部插入 ");
    LinkListPushFront(&phead,'x');
    LinkListPrintChar(phead," 头部插入 ");
    LinkListPopFront(&phead);
    LinkListPrintChar(phead," 头部删除 ");
}

void TestLinkListFind(){
    TestType;
    LinkNode* phead;
    LinkNode* cur;
    LinkListInit(&phead);
    LinkListPushBack(&phead,'a');
    LinkListPushBack(&phead,'b');
    LinkListPushBack(&phead,'c');
    LinkListPushBack(&phead,'d');
    LinkListPushBack(&phead,'e');
    LinkListPrintChar(phead," 插入五个元素 ");
    cur = LinkListFind(phead,'d');
    printf("要查找的元素位于[%p]\n",cur);
}

void TestLinkListInsert(){
    TestType;
    LinkNode* phead;
    LinkListInit(&phead);
    LinkListInsert(&phead,phead,'x');
    LinkListPrintChar(phead," 对空链表插入 ");
    LinkListPushBack(&phead,'a');
    LinkListPushBack(&phead,'b');
    LinkListPushBack(&phead,'c');
    LinkListPushBack(&phead,'d');
    LinkListPushBack(&phead,'e');
    LinkListPrintChar(phead," 尾部插入五个元素 ");
    LinkListInsert(&phead,NULL,'y');
    LinkListPrintChar(phead," pos = NULL ");
    LinkListInsert(&phead,phead,'z');
    LinkListPrintChar(phead," pos = phead ");
    LinkNode* pos = LinkListFind(phead,'c');
    LinkListInsert(&phead,pos,'m');
    LinkListPrintChar(phead," c位置插入m ");
}

void TestLinkListInsertAfter(){
    TestType;
    LinkNode* phead;
    LinkListInit(&phead);
    LinkListInsertAfter(&phead,phead,'x');
    LinkListPrintChar(phead," 对空链表插入 ");
    LinkListPushBack(&phead,'a');
    LinkListPushBack(&phead,'b');
    LinkListPushBack(&phead,'c');
    LinkListPushBack(&phead,'d');
    LinkListPushBack(&phead,'e');
    LinkListPrintChar(phead," 尾部插入五个元素 ");
    LinkListInsertAfter(&phead,NULL,'y');
    LinkListInsertAfter(&phead,phead,'z');
    LinkListPrintChar(phead," pos = phead ");
    LinkNode* pos = LinkListFind(phead,'c');
    LinkListInsertAfter(&phead,pos,'m');
    LinkListPrintChar(phead," c位置插入m ");
}

TestLinkListErase1(){
    TestType;
    LinkNode* phead;
    LinkListInit(&phead);
    LinkListPushBack(&phead,'a');
    LinkListPushBack(&phead,'b');
    LinkListPushBack(&phead,'c');
    LinkListPushBack(&phead,'d');
    LinkNode* pos = LinkListFind(phead,'d');
    LinkListErase1(&phead,phead);
    LinkListPrintChar(phead," 删除头节点 ");
    LinkListErase1(&phead,pos);
    LinkListPrintChar(phead," 删除d元素 ");
}

TestLinkListErase2(){
    TestType;
    LinkNode* phead;
    LinkListInit(&phead);
    LinkListPushBack(&phead,'a');
    LinkListPushBack(&phead,'b');
    LinkListPushBack(&phead,'c');
    LinkListPushBack(&phead,'d');
    LinkListPrintChar(phead," 尾插四个元素 ");
    LinkNode* posa = LinkListFind(phead,'a');
    LinkNode* posd = LinkListFind(phead,'d');
    LinkListErase2(&phead,&posa);
    LinkListPrintChar(phead," 删除a元素 ");
    LinkListErase2(&phead,&posd);
    LinkListPrintChar(phead," 删除d元素 ");
}

TestLinkListRemove(){
    TestType;
    LinkNode* phead;
    int empty;
    int count;
    LinkListInit(&phead);
    LinkListPushBack(&phead,'a');
    LinkListPushBack(&phead,'b');
    LinkListPushBack(&phead,'c');
    LinkListPushBack(&phead,'d');
    LinkListPrintChar(phead," 尾插四个元素 ");
    empty = LinkListEmpty(phead);
    printf("empty = [%d]\n",empty);
    count = LinkListSize(phead);
    printf("数组长度为:%d\n\n",count);
    LinkListRemove(&phead,'c');
    LinkListPrintChar(phead," 删除元素c ");
}

TestLinkListRemoveAll(){
    TestType;
    LinkNode* phead;
    LinkListInit(&phead);
    LinkListPushBack(&phead,'b');
    LinkListPushBack(&phead,'a');
    LinkListPushBack(&phead,'c');
    LinkListPushBack(&phead,'b');
    LinkListPushBack(&phead,'a');
    LinkListPushBack(&phead,'b');
    LinkListPushBack(&phead,'c');
    LinkListPushBack(&phead,'b');
    LinkListPrintChar(phead," 尾部插入元素 ");
    LinkListRemoveAll(&phead,'b');
    LinkListPrintChar(phead," 删除所有的b ");
}

int main(){
    TestInit();
    TestPushBack();
    TestLinkListPushFront();
    TestLinkListFind();
    TestLinkListInsert();
    TestLinkListInsertAfter();
    TestLinkListErase1();
    TestLinkListErase2();
    TestLinkListRemove();
    TestLinkListRemoveAll();
    return 0;
}

Makefile

linklist:linklist.c main.c
    gcc $^ -o -g $@
.PHONY:clean
clean:
    rm linklist

这是单链表的一些基本操作,在写单链表函数的时候最好在纸上画一下链表,只要理清增删改查得思路,代码自然而然的就能写出来,还有一些其它的操作,我将在之后的博客中介绍。


由于个人能力有限,以上的说明可能有Bug或者有什么不妥之处,欢迎发邮件到我的邮箱( Cyrus_wen@163.com )批评指正!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值