带头节点的单向链表(联系人列表)(C)

首先定义结点和头结点的内容,普通结点的数据域包含姓名、电话、公司信息,地址域保存下一个结点的地址。头结点数据域保存表长,地址域保存第一个结点地址。

struct PersonNode  //普通结点
{
    char name[NameLen];
    char phone[PhoneLen];
    char company[CompanyLen];

    struct PersonNode *pstNext;   //指针域:指向下一个结点
};

struct PLHead      //头结点
{
    int len;

    struct PersonNode *pstFirst;
};

普通结点动态分配内存和释放内存:

struct PersonNode *CreateNewNode(struct PersonNode *pstData)  //新结点动态分配内存空间
{
    struct PersonNode *pstNew = NULL;
    pstNew = (struct PersonNode *)malloc(sizeof(struct PersonNode));  //需要强制转换成struct类型的指针
    if(pstNew == NULL)
    {
        printf("Malloc failed!\n");
        return NULL;
    }
    if(pstData != NULL)
    {
        memcpy(pstNew,pstData,sizeof(struct PersonNode));  //把结点内容复制到动态分配的新结点的内存空间
        pstNew->pstNext = NULL;     //并让新结点的指针域清零
    }
    else
    {
        memset(pstNew,0,sizeof(struct PersonNode));
    }
    return pstNew;
}

int DestroyNode(struct PersonNode *pstNode)   //删除结点后释放内存空间
{
    if(pstNode != NULL)
    {
        free(pstNode);
        pstNode = NULL;
    }
    return 0;
}

头结点动态分配内存和释放内存,释放头结点即释放整个链表空间。

struct PLHead *CreatePLHead()  //头结点动态内存分配
{
    struct PLHead *pstNew = NULL;
    pstNew = (struct PLHead *)malloc(sizeof(struct PLHead));  //需要强制转换成struct类型的指针
    if(pstNew == NULL)
    {
        printf("Malloc failed!\n");
        return NULL;
    }

    memset(pstNew,0,sizeof(struct PLHead));

    return pstNew;
}

int DestroyPLHead(struct PLHead *pstHead)  //释放头结点即释放整个链表
{
    struct PersonNode *pstNode = NULL;
    struct PersonNode *pstNext = NULL;

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

    pstNode = pstHead->pstFirst;
    while(pstNode != NULL)
    {
        pstNext = pstNode->pstNext;
        DestoryNode(pstNode);
        pstNode = pstNext;
    }
    free(pstHead);  //最后不要忘了把头结点的内存释放掉
    pstHead = NULL;
    return 0;
}

在链表尾部插入一个新结点。
思路:用一个指针变量保存原链表的最后一个结点,让最后一个结点的指针域指向新结点,新结点的指针域指向NULL。最后不要忘了更新头结点中的表长信息。

int InsertPersonNodeAtTail(struct PLHead *pstHead,struct PersonNode *pstNewNode)  //在尾部插入新结点
{
    struct 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(struct PLHead *pstHead,struct PersonNode *pstNode)
{
    struct PersonNode *pstPrev = NULL;   //保存要删除的结点的上一个结点的地址
    struct 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)
            {
                pstPrev = pstTemp;
                break;
            }
            pstTemp = pstTemp->pstNext;
        }
        if(pstPrev == NULL)
        {
            return -1;
        }
        else
        {
            pstPrev->pstNext = pstNode->pstNext;
            pstNode->pstNext = NULL;
        }
    }
    pstHead->len--;
    return 0;
}

通过姓名查找结点:

struct PersonNode * SearchNodeByName(struct PLHead *pstHead,char *name)   //返回查找结点位置
{
    struct 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;
}

实现函数功能

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

#define NameLen 20
#define PhoneLen 12
#define CompanyLen 20

struct PersonNode  //普通结点
{
    char name[NameLen];
    char phone[PhoneLen];
    char company[CompanyLen];

    struct PersonNode *pstNext;   //指针域:指向下一个结点
};

struct PLHead      //头结点
{
    int len;

    struct PersonNode *pstFirst;
};

int DestroyNode(struct PersonNode *pstNode);
int PrintAllNode(struct PLHead *pstHead);

struct PLHead *CreatePLHead()  //头节点动态内存分配
{
    struct PLHead *pstNew = NULL;
    pstNew = (struct PLHead *)malloc(sizeof(struct PLHead));  //需要强制转换成struct类型的指针
    if(pstNew == NULL)
    {
        printf("Malloc failed!\n");
        return NULL;
    }

    memset(pstNew,0,sizeof(struct PLHead));

    return pstNew;
}

int DestroyPLHead(struct PLHead *pstHead)  //释放头节点即释放整个链表
{
    struct PersonNode *pstNode = NULL;
    struct PersonNode *pstNext = NULL;

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

    pstNode = pstHead->pstFirst;
    while(pstNode != NULL)
    {
        pstNext = pstNode->pstNext;
        DestoryNode(pstNode);
        pstNode = pstNext;
    }
    free(pstHead);  //最后不要忘了把头节点的内存释放掉
    pstHead = NULL;
    return 0;
}

struct PersonNode *CreateNewNode(struct PersonNode *pstData)  //新节点动态分配内存空间
{
    struct PersonNode *pstNew = NULL;
    pstNew = (struct PersonNode *)malloc(sizeof(struct PersonNode));  //需要强制转换成struct类型的指针
    if(pstNew == NULL)
    {
        printf("Malloc failed!\n");
        return NULL;
    }
    if(pstData != NULL)
    {
        memcpy(pstNew,pstData,sizeof(struct PersonNode));  //把节点内容复制到动态分配的新节点的内存空间
        pstNew->pstNext = NULL;     //并让新节点的指针域清零
    }
    else
    {
        memset(pstNew,0,sizeof(struct PersonNode));
    }
    return pstNew;
}

int DestroyNode(struct PersonNode *pstNode)   //删除节点后释放内存空间
{
    if(pstNode != NULL)
    {
        free(pstNode);
        pstNode = NULL;
    }
    return 0;
}

int InsertPersonNodeAtTail(struct PLHead *pstHead,struct PersonNode *pstNewNode)  //在尾部插入新节点
{
    struct 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(struct PLHead *pstHead,struct PersonNode *pstNode)
{
    struct PersonNode *pstPrev = NULL;   //保存要删除的节点的上一个节点的地址
    struct 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)
            {
                pstPrev = pstTemp;
                break;
            }
            pstTemp = pstTemp->pstNext;
        }
        if(pstPrev == NULL)
        {
            return -1;
        }
        else
        {
            pstPrev->pstNext = pstNode->pstNext;
            pstNode->pstNext = NULL;
        }
    }
    pstHead->len--;
    return 0;
}

struct PersonNode * SearchNodeByName(struct PLHead *pstHead,char *name)   //返回查找节点位置
{
    struct 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 main(int agrc,char *argv[])
{
    struct PLHead *pstHead = CreatePLHead();  //创造头节点
    struct PersonNode *pstNew = NULL;
    struct PersonNode NodeData = {""};

    strcpy(NodeData.name,"PiQi");
    strcpy(NodeData.name,"15600663787");
    strcpy(NodeData.company,"MicroSoft");
    pstNew = CreateNewNode(&NodeData);
    InsertPersonNodeAtTail(pstHead,pstNew);

    strcpy(NodeData.name,"ChenXinxin");
    strcpy(NodeData.name,"15600665727");
    strcpy(NodeData.company,"IBM");
    pstNew = CreateNewNode(&NodeData);
    InsertPersonNodeAtTail(pstHead,pstNew);

    strcpy(NodeData.name,"SuDongpo");
    strcpy(NodeData.name,"16619951990");
    strcpy(NodeData.company,"Microsoft");
    pstNew = CreateNewNode(&NodeData);
    InsertPersonNodeAtTail(pstHead,pstNew);

    PrintAllNode(pstHead);

    return 0;
}

int PrintAllNode(struct PLHead *pstHead)
{
    struct PersonNode *pstNode = NULL;
    if(pstHead == NULL)
    {
        return -1;
    }
    pstNode = pstHead->pstFirst;
    while(pstNode != NULL)
    {
        printf("Name:%s  PhoneNumber:%s  Company:%s\n",pstNode->name,pstNode->phone,pstNode->company);
        pstNode = pstNode->pstNext;
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值