通讯录(单链表解决)

本文展示了一个使用C语言编写的通讯录管理程序,采用单链表存储联系人信息。程序包含添加、删除、查找、修改、显示、清空和按姓名排序等操作。特别地,排序功能采用了冒泡排序算法对链表进行排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

目标需求:

一、菜单

二、功能0-退出

二、功能1-增加联系人

三、功能2-删除

四、功能3-查找

五、功能4-修改

六、功能5-显示联系人

七、功能6-清空通讯录

八、功能7-以名称排序

完整代码


目标需求:

 虽然只要求1000个人,但是看标题就知道我做的应该是不限制大小的,没错,我不知死活的用了单链表来存,给自己挖了一个坑,但相信我,链表,是可以做的!

一、菜单

一个平平无奇的菜单。

int menu()
{
    puts("***************************************************");
    puts("**********        通讯录1.0             ***********");
    puts("**********                              ***********");
    puts("**********  1.新增  2.删除     3.查找   ***********");
    puts("**********  4.修改       5.显示联系人   ***********");
    puts("**********  6清空通讯录   7.以名称排序  ***********");
    puts("********            0.退出                *********");
    puts("***************************************************");
    int i;
    scanf("%d", &i);
    return i;
}

二、功能0-退出

这是主函数的代码,首先我写了一个枚举类型来进行switch的判断,而退出只需要在选择0的时候直接退出程序就可以了,代码里我只是习惯用flag标记了,这个程序只做一件事,不用标记再退。

enum Choose
{
    EXIT,
    ADD,
    DEL,
    SEARCH,
    MODIFY,
    SHOW,
    CLEAN,
    SORT
};
int main()
{
    int flag = 0;
    struct data *head = (struct data *)malloc(sizeof(struct data));
    head->next = NULL;
    while (1)
    {
        switch (menu())
        {
        case EXIT:
            flag = 1;
            break;
        case ADD:
            add(head);
            break;
        case DEL:
            del(head);
            break;
        case SEARCH:
            sesrch(head);
            break;
        case MODIFY:
            modify(head);
            break;
        case SHOW:
            show(head);
            break;
        case CLEAN:
            clean(head);
            break;
        case SORT:
            sort(head);
            break;
        default:
            printf("输入错误,请重新输入\n");
            break;
        };
        if (flag)
            break;
    }
    return 0;
}

二、功能1-增加联系人

这里的链表的头节点我没有存数据,后面有大用处,需要注意新节点的next指针指向空指针,这个主要用于判断链表是否到末尾。

还有一个主要从用户角度出发,没有申请到内存的时候要提醒用户并退出

void add(struct data *p)
{

    if (p->next)
    { //如果为NULL则不会
        while (p->next)
        {
            p = p->next;
        }
    }
    p->next = (struct data *)malloc(sizeof(struct data));//防止
    if (p->next == NULL)
    {
        printf("内存申请失败,请重试或释放内存\n");
        return;
    }
    p = p->next; //指向最后个空的元素
    p->next = NULL;
    printf("请输入姓名\n");
    scanf("%s", p->name);
    printf("再输入输入姓别\n");
    scanf("%s", p->sex);
    printf("他\\她的年龄\n");
    scanf("%hd", &(p->age)); //注意用的short类型

    printf("他\\她地址\n");
    scanf("%s", p->address);
    printf("他\\她的电话\n");
    scanf("%s", p->phone);
}

三、功能2-删除

找到要删除的节点后,我们要把节点的上一位next修改为节点的next,由于单链表无法回溯,所以我们只能用两个指针,一个在另一个前面,后面的那个指针用于判断

void del(struct data *p)
{
    if (!p->next)
    {
        printf("通讯录为空\n");
        return;
    }
    printf("请输入你要删除的人的性名\n");
    char n[MAX_NAME];
    scanf("%s", n);
    int i;
    struct data *t = p;
    while (1)
    {
        t = p;
        p = p->next;
        i = 0;
        while (p->name[i] == n[i])
        {
            if (!(p->name[i]) || !(n[i]))
                break;
            i++;
        }
        if (p->name[i] == n[i])
        {
            t->next = p->next;
            free(p);
            return;
        }
        if (p->next == NULL)
            break;
    }
    printf("查无此人\n");
}

四、功能3-查找

查找到之后如果使用左对齐可以更好的表现出表格效果哦!

void sesrch(struct data *p)
{
    if (!p->next)
    {
        printf("通讯录为空\n");
        return;
    }
    printf("请输入你要查询的人的性名\n");
    char n[MAX_NAME];
    scanf("%s", n);

    int i;
    struct data *t = p;
    while (1)
    {
        t = p;
        p = p->next;
        i = 0;
        while (p->name[i] == n[i])
        {
            if (!(p->name[i]) || !(n[i]))
                break;
            i++;
        }
        if (p->name[i] == n[i])
        {
            printf("姓名          姓别         年龄         地址       电话\n");
            printf("%-14s%-13s%-13hd%-12s%s\n", p->name, p->sex, (p->age), p->address, p->phone);
            return;
        }
        if (p->next == NULL)
            break;
    }
    printf("查无此人\n");
}

五、功能4-修改

查找之后多了个功能,不用说了吧


void modify(struct data *p)
{
    if (!p->next)
    {
        printf("通讯录为空\n");
        return;
    }
    printf("请输入你要修改的人的性名\n");
    char n[MAX_NAME];
    scanf("%s", n);

    int i, j;
    struct data *t = p;
    while (1)
    {
        t = p;
        p = p->next;
        i = 0;
        while (p->name[i] == n[i])
        {
            if (!(p->name[i]) || !(n[i]))
                break;
            i++;
        }
        if (p->name[i] == n[i])
        {

            while (1)
            {
                printf("请输入你要修改哪一项\n1.姓名 2.姓别 3.年龄 4.地址 5.电话 0.修改完毕\n");
                scanf("%d", &j);
                switch (j)
                {
                case EXIT:
                    return;
                    break;
                case 1:
                    printf("请修改后的姓名\n");
                    scanf("%s", p->name);
                    break;
                case 2:
                    printf("请修改后的姓别\n");
                    scanf("%s", p->sex);
                    break;
                case 3:
                    printf("请修改后的年龄\n");
                    scanf("%hd", &(p->age));
                    break;
                case 4:
                    printf("请修改后的地址\n");
                    scanf("%s", p->address);
                    break;
                case 5:
                    printf("请修改后的电话\n");
                    scanf("%s", p->phone);
                    break;
                default:
                    printf("输入错误,请重新输入\n");
                    break;
                };
            }
            return;
        }
        if (p->next == NULL)
            break;
    }
    printf("查无此人\n");
}

六、功能5-显示联系人

同样运用了左对齐

void show(struct data *p)
{

    printf("姓名          姓别         年龄         地址       电话\n");
    while (p->next)
    {
        p = p->next;
        printf("%-14s%-13s%-13hd%-12s%s\n", p->name, p->sex, (p->age), p->address, p->phone);
    }
}

七、功能6-清空通讯录

删除节点就行了,记得释放空间

void clean(struct data *p)
{

    struct data *t = p->next;
    p->next = NULL;
    if (t)
        p = t->next;
    else
    {
        printf("通讯录为空\n");
        return;
    }
    while (1)
    {
        free(t);
        t = p;
        if (p)
            p = p->next;
        else
            break;
    }
    free(p);
    return;
}

八、功能7-以名称排序

重点来了,敲黑板!

这里我对整个结构体进行了排序,首先我们可以写一个交换结构体节点的交换函数。

void E(struct data *p1, struct data *p2, struct data *h)
{

    struct data *t1 = h, *t2 = h;
    while (t1->next != p1)
    {
        t1 = t1->next;
    }
    while (t2->next != p2)
    {
        t2 = t1->next;
    }
    t1->next = p2;
    t2->next = p1;
    t1 = p1->next;
    p1->next = p2->next;
    p2->next = t1;
}

排序方法我用的冒泡排序,因为用到结构体上比较简单。

因为链表的大小我们不知道,所以我们要在函数内计算大小,

为什么我在交换的时候要用两个指针暂存然后先前往下一位呢呢?因为交换了元素之后节点向下移动就不会是原来的下一个了,

平常我们的交换元素就像交换火车车厢里的人,这里的交换就是直接交换车厢。

void sort(struct data *p)
{
    if (!(p->next && (p->next)->next))
    {
        printf("目前不需要排序\n");
        return;
    }
    struct data *t1 = p, *t2;
    int count = 0;
    while (t1)
    {
        t1 = t1->next;
        count++;
    }
    count--;
    struct data *a,*b;
    int i, j;
    for (i = 0; i < count - 1; i++)
    {
        t1 = p->next;
        t2 = t1->next;
        for (j = 0; j < count - i - 1; j++)
        {
            a=t1,b=t2;
            t1 = t1->next;
            t2 = t2->next;
            if (strcmp(a->name, b->name) > 0)
                E(a, b, p);
        }
    }
}

完整代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_NAME 24
#define SEX 14
#define MAX_AD 100
#define MAX_PHONE 24
struct data
{
    char name[MAX_NAME];
    char sex[SEX];
    short age; // hd  岁数最多一百多吧
    char address[MAX_AD];
    char phone[MAX_PHONE];
    struct data *next;
};
enum Choose
{
    EXIT,
    ADD,
    DEL,
    SEARCH,
    MODIFY,
    SHOW,
    CLEAN,
    SORT
};
int menu();
void add(struct data *p);
void show(struct data *p);
void del(struct data *p);
void sesrch(struct data *p);
void modify(struct data *p);
void clean(struct data *p);
void sort(struct data *p);
void E(struct data *p1, struct data *p2, struct data *h);//链表节点的交换
int main()
{
    int flag = 0;
    struct data *head = (struct data *)malloc(sizeof(struct data));
    head->next = NULL;
    while (1)
    {
        switch (menu())
        {
        case EXIT:
            flag = 1;
            break;
        case ADD:
            add(head);
            break;
        case DEL:
            del(head);
            break;
        case SEARCH:
            sesrch(head);
            break;
        case MODIFY:
            modify(head);
            break;
        case SHOW:
            show(head);
            break;
        case CLEAN:
            clean(head);
            break;
        case SORT:
            sort(head);
            break;
        default:
            printf("输入错误,请重新输入\n");
            break;
        };
        if (flag)
            break;
    }
    return 0;
}

int menu()
{
    puts("***************************************************");
    puts("**********        通讯录1.0             ***********");
    puts("**********                              ***********");
    puts("**********  1.新增  2.删除     3.查找   ***********");
    puts("**********  4.修改       5.显示联系人   ***********");
    puts("**********  6清空通讯录   7.以名称排序  ***********");
    puts("********            0.退出                *********");
    puts("***************************************************");
    int i;
    scanf("%d", &i);
    return i;
}
void add(struct data *p)
{

    if (p->next)
    { //如果为NULL则不会
        while (p->next)
        {
            p = p->next;
        }
    }
    p->next = (struct data *)malloc(sizeof(struct data));//防止
    if (p->next == NULL)
    {
        printf("内存申请失败,请重试或释放内存\n");
        return;
    }
    p = p->next; //指向最后个空的元素
    p->next = NULL;
    printf("请输入姓名\n");
    scanf("%s", p->name);
    printf("再输入输入姓别\n");
    scanf("%s", p->sex);
    printf("他\\她的年龄\n");
    scanf("%hd", &(p->age)); //注意用的short类型

    printf("他\\她地址\n");
    scanf("%s", p->address);
    printf("他\\她的电话\n");
    scanf("%s", p->phone);
}
void show(struct data *p)
{

    printf("姓名          姓别         年龄         地址       电话\n");
    while (p->next)
    {
        p = p->next;
        printf("%-14s%-13s%-13hd%-12s%s\n", p->name, p->sex, (p->age), p->address, p->phone);
    }
}
void del(struct data *p)
{
    if (!p->next)
    {
        printf("通讯录为空\n");
        return;
    }
    printf("请输入你要删除的人的性名\n");
    char n[MAX_NAME];
    scanf("%s", n);
    int i;
    struct data *t = p;
    while (1)
    {
        t = p;
        p = p->next;
        i = 0;
        while (p->name[i] == n[i])
        {
            if (!(p->name[i]) || !(n[i]))
                break;
            i++;
        }
        if (p->name[i] == n[i])
        {
            t->next = p->next;
            free(p);
            return;
        }
        if (p->next == NULL)
            break;
    }
    printf("查无此人\n");
}
void sesrch(struct data *p)
{
    if (!p->next)
    {
        printf("通讯录为空\n");
        return;
    }
    printf("请输入你要查询的人的性名\n");
    char n[MAX_NAME];
    scanf("%s", n);

    int i;
    struct data *t = p;
    while (1)
    {
        t = p;
        p = p->next;
        i = 0;
        while (p->name[i] == n[i])
        {
            if (!(p->name[i]) || !(n[i]))
                break;
            i++;
        }
        if (p->name[i] == n[i])
        {
            printf("姓名          姓别         年龄         地址       电话\n");
            printf("%-14s%-13s%-13hd%-12s%s\n", p->name, p->sex, (p->age), p->address, p->phone);
            return;
        }
        if (p->next == NULL)
            break;
    }
    printf("查无此人\n");
}

void modify(struct data *p)
{
    if (!p->next)
    {
        printf("通讯录为空\n");
        return;
    }
    printf("请输入你要修改的人的性名\n");
    char n[MAX_NAME];
    scanf("%s", n);

    int i, j;
    struct data *t = p;
    while (1)
    {
        t = p;
        p = p->next;
        i = 0;
        while (p->name[i] == n[i])
        {
            if (!(p->name[i]) || !(n[i]))
                break;
            i++;
        }
        if (p->name[i] == n[i])
        {

            while (1)
            {
                printf("请输入你要修改哪一项\n1.姓名 2.姓别 3.年龄 4.地址 5.电话 0.修改完毕\n");
                scanf("%d", &j);
                switch (j)
                {
                case EXIT:
                    return;
                    break;
                case 1:
                    printf("请修改后的姓名\n");
                    scanf("%s", p->name);
                    break;
                case 2:
                    printf("请修改后的姓别\n");
                    scanf("%s", p->sex);
                    break;
                case 3:
                    printf("请修改后的年龄\n");
                    scanf("%hd", &(p->age));
                    break;
                case 4:
                    printf("请修改后的地址\n");
                    scanf("%s", p->address);
                    break;
                case 5:
                    printf("请修改后的电话\n");
                    scanf("%s", p->phone);
                    break;
                default:
                    printf("输入错误,请重新输入\n");
                    break;
                };
            }
            return;
        }
        if (p->next == NULL)
            break;
    }
    printf("查无此人\n");
}
void clean(struct data *p)
{

    struct data *t = p->next;
    p->next = NULL;
    if (t)
        p = t->next;
    else
    {
        printf("通讯录为空\n");
        return;
    }
    while (1)
    {
        free(t);
        t = p;
        if (p)
            p = p->next;
        else
            break;
    }
    free(p);
    return;
}
void sort(struct data *p)
{
    if (!(p->next && (p->next)->next))
    {
        printf("目前不需要排序\n");
        return;
    }
    struct data *t1 = p, *t2;
    int count = 0;
    while (t1)
    {
        t1 = t1->next;
        count++;
    }
    count--;
    struct data *a,*b;
    int i, j;
    for (i = 0; i < count - 1; i++)
    {
        t1 = p->next;
        t2 = t1->next;
        for (j = 0; j < count - i - 1; j++)
        {
            a=t1,b=t2;
            t1 = t1->next;
            t2 = t2->next;
            if (strcmp(a->name, b->name) > 0)
                E(a, b, p);
        }
    }
}
void E(struct data *p1, struct data *p2, struct data *h)
{

    struct data *t1 = h, *t2 = h;
    while (t1->next != p1)
    {
        t1 = t1->next;
    }
    while (t2->next != p2)
    {
        t2 = t1->next;
    }
    t1->next = p2;
    t2->next = p1;
    t1 = p1->next;
    p1->next = p2->next;
    p2->next = t1;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值