C语言之单链表(头结点与节点结构不相同)

上代码:

头文件:

#ifndef __PLINK_H
#define __PLINK_H

#define NAME_LEN 20
#define PHONE_LEN 20
#define COMPANY_LEN 20

typedef struct PersonNode
{
    char name[NAME_LEN];
    char phone[PHONE_LEN];
    char company[COMPANY_LEN];
    struct PersonNode *pstNext;

}PersonNode;

typedef struct
{
    int len;
    PersonNode *pstFirst;

}PLHead;

int SingleLinkList(void);

int DestroyPLHead(PLHead *pstHead);
PLHead * CreatePLHead();

int DestroyNode(PersonNode *pstNode);           //释放内存空间(free)
PersonNode *CreateNewNode(PersonNode *pstData); //申请内存空间(malloc)
PersonNode *SearchNodeName(PLHead *pstHead, char *name);    //搜索第几个节点的信息
int AddPersonNode(PLHead *pstHead, PersonNode *pstNewNode); //追加一个节点
int RemovePersonNode(PLHead *pstHead, PersonNode *pstNode); //移除1个节点
int InsertPersonNode(PLHead *pstHead, PersonNode *pstNewNode, int addCount);//插入或追加1一个节点

源文件(.c)

/*
C语言数据结构与算法
带头结点的单链表

程序思路:
创建一个头结点
1.CreatePLHead()函数创建一个头结点

向单链表添加节点
1.定义PersonNode结构体变量存放节点的内容信息
2.使用CreateNewNode(&PersonNode)申请内存,将结构体PersonNode的内容信息复制到改内存中
3.使用AddPersonNode()或InsertPersonNode()函数向单链表添加节点

删除单链表的某一个节点
1.使用SearchNodeName()函数搜索你要删除的节点
2.使用RemovePersonNode()函数,将搜索到的节点从单链表中删除
3.使用DestroyNode()函数,将搜索到要删除的节点的内存free()释放掉
*/

#include "PLink.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//删除整条链表的内存空间
int DestroyPLHead(PLHead *pstHead)  
{
    PersonNode *pstNext = NULL;
    PersonNode *pstNode = NULL;

    if(pstHead == NULL)
    {
        return -1;
    }

    pstNode = pstHead->pstFirst;
    while(pstNext != NULL)
    {
        pstNext = pstNode->pstNext;
        DestroyNode(pstNode);
        pstNode = pstNext;
    }
    free(pstHead);
    pstHead = NULL;

    return 0;
}

//创建头结点
PLHead * CreatePLHead()
{
    PLHead *pstNew = NULL;

    pstNew = (PLHead *)malloc(sizeof(PLHead) );
    if(pstNew == NULL)
    {
        printf("Error malloc failed\n");
        return NULL;
    }
    memset(pstNew, 0, sizeof(PLHead));

    return pstNew;
}

//删除节点的内存
int DestroyNode(PersonNode *pstNode)
{
    if(pstNode == NULL)
    {
        return -1;
    }
    else
    {
        free(pstNode);
        pstNode = NULL;
    }

    return 0;
}

//创建节点申请内存
PersonNode *CreateNewNode(PersonNode *pstData) //申请内存空间(malloc)
{
    PersonNode *pstNew = NULL;

    pstNew = (PersonNode *)malloc(sizeof(PersonNode) );
    if(pstNew == NULL)
    {
        printf("Error malloc failed\n");
        return NULL;
    }

    if(pstData != NULL)
    {
        memcpy(pstNew, pstData, sizeof(PersonNode) );
    }
    else
    {
        memset(pstNew, 0, sizeof(PersonNode));
    }

    return pstNew;
}

//在链表末尾追加一个节点
int AddPersonNode(PLHead *pstHead, PersonNode *pstNewNode)
{
    PersonNode *pstLast = NULL;

    if(pstHead == NULL || pstNewNode == NULL)
    {
        return -1;
    }

    pstLast = pstHead->pstFirst;
    while (pstLast != NULL)
    {
        if(pstLast->pstNext == NULL) break;     //判断是否最后一个节点
        pstLast = pstLast->pstNext;
    }

    if(pstLast == NULL)                 //空链表情况下
    {
        pstHead->pstFirst = pstNewNode;
    }
    else                                //非空链表情况下
    {
        pstLast->pstNext = pstNewNode;
    }
    pstNewNode->pstNext = NULL;
    pstHead->len++;

    return 0;
}

//在链表中移除一个节点
int RemovePersonNode(PLHead *pstHead, PersonNode *pstNode)
{
    PersonNode *pstPrev = NULL;
    PersonNode *pstTemp = NULL;

    if(pstHead == NULL || pstNode == NULL) return -1;

    pstTemp = pstHead->pstFirst;
    if(pstTemp == NULL) return -1;  //空链表

    if(pstTemp == pstNode)          //删除第一个节点
    {
        pstHead->pstFirst = pstNode->pstNext;
        pstNode->pstNext = NULL;
    }
    else
    {
        while(pstTemp != NULL)
        {
            if(pstTemp->pstNext == pstNode) //查询直到pstNode的上一个节点
            {
                pstPrev = pstTemp;          //保存目标节点的上一个节点
                pstTemp = pstTemp->pstNext;     //目标节点
                break;
            }
            pstTemp = pstTemp->pstNext;     //目标节点
        }
        if(NULL == pstPrev)
        {
            return -1;
        }
        else
        {
            pstPrev->pstNext = pstTemp->pstNext;
            pstNode->pstNext = NULL;
        }
    }

    pstHead->len--;

    return 0;
}

//在链表中搜索一个节点
PersonNode *SearchNodeName(PLHead *pstHead, char *name)
{
    PersonNode *pstNode = NULL;

    if(pstHead == NULL || name == NULL) return NULL;

    pstNode = pstHead->pstFirst;
    while(pstNode != NULL)
    {
        if(strcmp(pstNode->name, name) == 0) break;
        pstNode = pstNode->pstNext;
    }

    return pstNode;
}

//在链表中指定的位置插入一个节点
int InsertPersonNode(PLHead *pstHead, PersonNode *pstNewNode, int addCount)
{
    PersonNode *pst = NULL;
    int count = addCount;

    if(pstHead == NULL || pstNewNode == NULL || addCount <= 0 )//有头节点Head, addcount==0会把头节点移位
    {
        return -1;
    }
    if(addCount > pstHead->len)
    {
        if(addCount - pstHead->len == 1)    //如果输入的addcount刚好在末尾处,则追加
        {
            AddPersonNode(pstHead, pstNewNode);
            return 0;
        }
        else
        {
            return -1;                      //输入的addcount超出链表范围
        }

    }

    pst = pstHead->pstFirst;
    count--;

    while (count--)
    {
        if(count == 0) break;
        pst = pst->pstNext;
    }
    if(addCount == 1)                   //要插在第1个节点
    {
        pstNewNode->pstNext = pst;
        pstHead->pstFirst = pstNewNode;
    }
    else
    {
        pstNewNode->pstNext = pst->pstNext;
        pst->pstNext = pstNewNode;
    }

    pstHead->len++;

    return 0;
}

测试代码:

//填写节点信息
int PersonData(PersonNode *pstData, char *name, char *phone, char *company)
{
    strcpy(pstData->name, name);
    strcpy(pstData->phone, phone);
    strcpy(pstData->company, company);

    return 0;
}

//打印链表
int PrintfPersonData(PLHead *pstHead)
{
    PersonNode * pstNode = NULL;
    if(pstHead == NULL) return -1;

    pstNode = pstHead->pstFirst;
    while(pstNode != NULL)
    {
        printf("name:%s  phone:%s  company:%s\n", pstNode->name, pstNode->phone, pstNode->company);
        pstNode = pstNode->pstNext;
    }

    return 0;
}

//测试函数
int SingleLinkList(void)
{
    PLHead *pstHead = CreatePLHead();
    PersonNode *pstNew = NULL;
    PersonNode personData ;
    PersonNode *SearchName = NULL;

    PersonData(&personData, "111", "1111111111", "Fly");    //节点数据
    pstNew = CreateNewNode(&personData);        //创建新的节点
//    AddPersonNode(pstHead, pstNew);
    InsertPersonNode(pstHead, pstNew, 1);             //向链表添加新的节点

    PersonData(&personData, "222", "22222222222", "NBA");
    pstNew = CreateNewNode(&personData);
    AddPersonNode(pstHead, pstNew);     //自动追加到链表末尾

    PersonData(&personData, "333", "33333333333", "FBI");
    pstNew = CreateNewNode(&personData);
    InsertPersonNode(pstHead, pstNew, 2);

    PersonData(&personData, "444", "44444444444", "FBI");
    pstNew = CreateNewNode(&personData);
    InsertPersonNode(pstHead, pstNew, 4);

    PrintfPersonData(pstHead);      //打印链表信息

    SearchName = SearchNodeName(pstHead, "444");   //查找name
    printf("SearchName//name:%s  phone:%s  company:%s\n\n", SearchName->name, SearchName->phone, SearchName->company);

    if(SearchName == NULL)
    {
        printf("Not find the name");
    }
    else
    {
        RemovePersonNode(pstHead, SearchName);
        PrintfPersonData(pstHead);      //打印链表信息
        printf("\nhas been remove the Jack\n");
        DestroyNode(SearchName);
    }

    PrintfPersonData(pstHead);      //打印链表信息

    return 0;
}

代码效果图:
C语言之单链表(头结点与节点结构不相同)