欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-03-15 17:37:02
...

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

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;
}