单链表的基本操作

单向不带环不带头结点的链表
实现功能:
1、初始化
2、销毁
3、尾插
4、尾删
5、头插
6、头删
7、在pos之后插入新结点
8、在pos之前插入新结点
9、删除指定位置的结点
10、查找结点的位置

代码实现:

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** phead,LinkNodeType value);//尾插

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

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

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

void LinkListInsert(LinkNode* pos,LinkNodeType value);//在pos之后插入新结点

void LinkListInsertBefore(LinkNode** phead,LinkNode* pos,LinkNodeType value);//在pos之前插入新结点(方法1)

void LinkListInsertBefore2(LinkNode* pos,LinkNodeType value);//在pos之前插入新结点(方法2)

void LinkListErase(LinkNode** phead,LinkNode* pos);//删除指定位置的结点(方法1)

void LinkListErase2(LinkNode** phead,LinkNode* pos);//删除置顶位置的结点(方法2)

LinkNode* LinkListFind(LinkNode* head,LinkNodeType to_find);//查找结点的位置

linklist.c


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

LinkNode* CreatNode(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(PLinkNode* phead){
    (void)phead;
}


void LinkListPushBack(LinkNode** phead,LinkNodeType value){
    if(phead == NULL){
        //非法输入
        return;
    }
    if(*phead == NULL){
        //空链表
        *phead = CreatNode(value);       
        return;
    }
    //链表非空
    LinkNode* cur = *phead;
    while(cur->next != NULL){
        cur = cur->next;
    }
    LinkNode* new_node = CreatNode(value);
    cur->next = new_node;
    //new_node->next = NULL;
    return;
}


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;
    }
    //当循环结束,cur就指向了最后一个节点
     //pre就指向了倒数第二个节点
    pre->next = NULL;
    DestroyNode(cur);
    return;
}

void LinkListPushFront(LinkNode** phead,LinkNodeType value){
    if(phead == NULL){
        //非法输入
        return;
    }
    LinkNode* new_node = CreatNode(value);
    new_node->next = *phead;
    *phead = new_node;
    return;
}

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){
    if(pos ==NULL){
        //非法输入,pos表示一个节点的指针,如果pos为空,说明根本不存在这样的节点
        return;
    }
    LinkNode* new_node = CreatNode(value);
    new_node->next = pos->next;
    pos->next = new_node;
    return;
}

void LinkListInsertBefore(LinkNode** phead,LinkNode* pos,LinkNodeType value){
    if(phead == NULL || pos == NULL){
        //非法输入
        return;
    }
    if(*phead == pos){
        //要插入的位置刚好是头节点
        LinkListPushFront(phead,value);
        return;
    }
    LinkNode* cur = *phead;
    for(;cur != NULL;cur = cur = cur->next){
        if(cur->next ==pos){
            break;
        }
    }
    //循环结束之后,需要知道是由于哪种情况下导致的循环结束,到底是找到了pos,还是没找到。
    if(cur == NULL){
        return;
    }
    LinkListInsert(cur,value);
    return;
}

void LinkListInsertBefore2(LinkNode* pos,LinkNodeType value){
    if(pos == NULL){
        //非法输入
        return;
    }
    LinkNode* new_node = CreatNode(pos->data);
    new_node->next = pos->next;
    pos->next = new_node;
    pos->data =value;
}

void LinkListErase(LinkNode** phead,LinkNode* pos){
    if(phead == NULL || pos ==NULL){
        //非法输入
        return;
    }
    if(*phead == NULL){
        //空链表
        return;
    }
    LinkNode* cur = *phead;
    for(;cur != NULL;cur = cur->next){
        if(cur->next == pos){
            break;
        }
    }
    //循环结束之后,要去判定,到底是找到了退出的。还是没找到pos退出的。
    if(cur == NULL){
        return;
    }
    cur->next = pos->next;
    DestroyNode(pos);
    return;
}

void LinkListErase2(LinkNode** phead,LinkNode* pos){
    if(phead == NULL || pos == NULL){
        //非法输入
        return;
    }
    if(*phead == NULL){
        return;
    }
    if(pos->next == NULL){
        //要删除的元素刚好是最后一个元素,只能使用原来的尾删的方式来删除了,这时候仍然得遍历链表
        LinkListPopBack(phead);
        return;
    }
    pos->data = pos->next->data;
    LinkNode* to_erase = pos->next;
    pos->next = to_erase->next;
    DestroyNode(to_erase);
    return;
}

LinkNode* LinkListFind(LinkNode* head,LinkNodeType to_find){
    if(head == NULL){
        //空链表
        return NULL;
    }
    LinkNode* cur = head;
    while(cur){
        if(cur->data == to_find){
            return cur;
        }
        cur = cur->next;
    }
    return NULL;
}

//
//以下为测试代码/
/
#if 1
#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,"尝试对空链表头删");

    LinkListPushBack(&head,'a');
    LinkListPushBack(&head,'b');
    LinkListPushBack(&head,'c');
    LinkListPushBack(&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,"在b之后插入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,"向头节点之前插入节点");

    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;
    LinkListInsertBefore2(pos1,'x');
    LinkListPrintChar(head,"向头节点之前插入节点");

    LinkNode* pos2 = head->next->next;
    LinkListInsertBefore2(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->next;
    LinkListErase(&head,pos);
    LinkListPrintChar(head,"删除元素b");

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

void TestErase2(){
    TEST_HEADER;
    LinkNode* head;
    LinkListInit(&head);
    LinkListErase2(&head,(LinkNode*)0x11);
    LinkListPrintChar(head,"尝试对空链表删除");

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

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

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

    LinkListPushBack(&head,'a');
    LinkListPushBack(&head,'b');
    LinkListPushBack(&head,'c');
    LinkListPushBack(&head,'d');
    LinkNode* pos_x = LinkListFind(head,'x');
    printf("pos_x expected NULL,actual %p\n",pos_x);
    LinkNode* pos_b = LinkListFind(head,'b');
    printf("pos_b expected %p,actual %p\n",head->next,pos_b);

}

int main(){
    TestInit();
    TestPushBack();
    TestPopBack();
    TestPushFront();
    TestPopFront();
    TestInsert();
    TestInsertBefore();
    TestInsertBefore2();
    TestErase();
    TestErase2();
    TestFind();
    return 0;
}


#endif

运行结果:

这里写图片描述
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值