C语言单链表编写电话簿

这次利用单链表做了一个简单的电话簿
这是程序中用到的头文件:

#include"stdio.h"
#include"string.h"
#include"stdlib.h"
#include"malloc.h"
#include"ctype.h"

首先在这里定义了一个结构体,这个结构体包含两部分 ,一个是指针域,另一个是数据域,数据域也是一个结构体,里面包含了联系人的姓名和电话号码。

typedef char DataType;
typedef struct Node{//定义
    struct {
        char name[20];
        char number[12];
    }data;
    char name[20];
    char number[12];
    struct  Node *next;
}LNode,*LinkList;

这里首先定义了一个头结点,这个是全局变量,这样定义就不用在各个函数之间来回传参数了,头结点的内存空间已经在主函数内申请了,所以下面可以直接使用

LinkList L;

首先,链表的插入方法有两种一种是头插法,一种是尾插法,不懂得小伙伴可以百度去查一下,这里就不进行过多的介绍了。
两种插入方法这里都有,大家可以自由选择。下面这一部分用的是头插法,简单来说就是先存入的在后面。大家可以自己试一下。

void CreateLinkList(){//头插
    LNode *s;
    DataType x=1;

    while(x!=2){
        s=(LinkList)malloc(sizeof(LNode));
        printf("请输入联系人姓名:");
        scanf("%s",s->data.name);
        printf("请输入联系人电话号码:");
       	CheckLinkList();
            s->next=L->next;
            L->next=s;
            printf("添加成功!是否继续新建联系人?\t");
            printf("1.是     2.否\n");
            scanf ("%d",&x);
    }
    printf("头插法插入已完成!\n");
    printf("请选择你的操作:");
}

这里是尾插法,与头插法的区别就是先插入的在前面。

void CreateLinkList2(){//尾插
    LNode *r,*s;
    int  x=1;
    r=L;
    while(x!=2){
            s=(LinkList)malloc(sizeof(LNode));
            printf("请输入联系人姓名:");
            scanf("%s",s->data.name);
            printf("请输入联系人电话号码:");

           CheckLinkList();
            r->next=s;
            r=s;
            printf("添加成功!是否继续新建联系人?\t");
            printf("1.是     2.否\n");
            scanf ("%d",&x);
    }
    r->next=NULL;
    printf("尾插法插入已完成!\n");
    printf("请选择你的操作:");
}

输入需要查找的内容进行查找,内容包括姓名和电话,两者选择一种都可以。
找到后返回找到的该结点,如果没有找到就返回尾节点。

LNode *LocationLinkList(){//按值查找
    LNode *p;
    int len;
    DataType x;
    char message[20];
    p=L->next;
    printf("请输入要查找的信息:");
    scanf("%s",message);
    if(!isdigit(message[0])){ //通过姓名查找
       loop: while(p!=NULL){
                if(strcmp(message,p->data.name)==0){
                    return p;
                }
                 else
                    p=p->next;
           }
            return p;
    }
    else {//通过号码查找查找
            if(strlen(message)!=11)
                goto loop;
            while(p!=NULL){
                if(strcmp(message,p->data.number)==0){

                    return p;
                }
            p=p->next;
        }
        return p;
    }
}

输入需要查找的位置,也就是序号进行查找。找到后返回找到的结点,如果没有找到就返回尾节点。

LNode *GetLinkList(int i){//按序号查找
    LNode *p;
    int j;
    p=L;
    j=0;
    while((p!=NULL)&&(i>j)){
        p=p->next;
        j++;
    }
    return p;
}

在链表中第i个位置插入新结点,需要先找到需要插入的位置再插入。这里用的是按号查找,只需要找到对应位置插入即可,当然也可以使用按内容查找,如在某人前插入,或者在某人后插入都可以。但是不建议大家用按内容查找因为比较繁琐麻烦。

void InsertLinkList(){//插入
    LNode *p,*s;
    int i;
    DataType x;
    printf("请输入需要插入的位置:");
    scanf("%d",&i);
    p=GetLinkList(i-1);
    if(p==NULL){
        printf("插入位置不合法!");
        exit (1);
    }
    else{
        s=(LinkList)malloc(sizeof(LNode));
        printf("请输入需要插入的联系人姓名:");
        scanf("%s",s->data.name);
        printf("请输入需要插入的联系人电话:");

       CheckLinkList();

        s->next=p->next;
        p->next=s;
    }
    printf("添加成功!");
    printf("请选择你的操作:");
}

,需要删除某一内容就需要先找到这个家电。这里可以对查找方式进行选择。不论查找方法是什么,最后都是将找到的这个结点返回,查找过程对该结点的前后结点没有影响。
还有要强调的是要释放已删除结点的空间,毕竟电脑内存是有限的,总是将内存分配出去不释放早晚有一天会用完的。

void DeleteLinkList(){//删除第i个结点
    LNode *p,*q;
    int i;
    p=SelectFind();
    if(p==NULL||p->next==NULL){//第i个结点的前驱不存在
        printf("删除不合法位置!");
        exit(1);
    }
    else{
        q=p->next;
        p->next=p->next->next;
        free(q);
    }
    printf("删除完成!\n");
    printf("请选择你的操作:");
}

这里是求表长,一个简单的计数器。其实也可以在定义结构体时添加一个llength。每新建一个联系人length++,删除一个联系人就length–。也是可以的。这里是把求长度的方法单独写出来了。

int LengthLinkList(){//求表长
    int len;
    LNode *p;
    p=L;
    len=0;
    while (p->next){
        len++;
        p=p->next;
    }
    return len;
}

一个简单的倒序,就比如原先顺序是123456,经过倒序后变成654321。

void ReverseLinkList(){//逆置
    LNode *p,*q;
    p=L->next;
    L->next=NULL;
    while(p){
        q=p;
        p=p->next;
        q->next=L->next;
        L->next=q;
    }
    printf("逆置完成!\n");
    printf("请选择你的操作:");
}

修改链表(电话簿)中的内容,这里可以可以对查找方式进行选择。

void ChargeLinkLIst (){//修改
    int i,len;
    LNode *s;
    len=LengthLinkList();
    printf("请输入要修改的位置:");
    loop: scanf("%d",&i);
    if(i>len|| i<0)
    {
        printf("此位置暂无联系人,无法修改,请重新输入:");
        goto loop;
    }
    s=SelectFind();
    printf("请输入更改后的名字:");
    scanf("%s",s->data.name);
    printf("请输入更改后的号码:");
 	CheckLinkList();
    printf("修改完成!");
    printf("请选择你的操作:");
}

简单的按链表的顺序将每一个结点中的内容都打印出来。

void PrintLinkList(){//打印
    LNode *p;
    p=L;
    printf("姓名\t\t电话\n\n");
    while(p->next!=NULL){
        p=p->next;
        printf("%s\t%s\n",p->data.name,p->data.number);
    }
    printf("打印完成:");
    printf("请选择你的操作:");
}

主菜单方便用户操作,选择。

void menuLinkList(){//主菜单
    printf("                           电话簿\n");
    printf("------------------------------------------------------------------\n");
    printf(" 菜单选项:\n");
    printf("  1   ---------------------------------------   头插法新建电话簿\n");
    printf("  2   ---------------------------------------   尾插法新建电话簿\n");
    printf("  3   ---------------------------------------   插入\n");
    printf("  4   ---------------------------------------   删除\n");
    printf("  5   ---------------------------------------   查找\n");
    printf("  6   ---------------------------------------   修改\n");
    printf("  7   ---------------------------------------   计数\n");
    printf("  8   ---------------------------------------   逆置\n");
    printf("  9   ---------------------------------------   输出\n");
    printf("  10  ---------------------------------------   清屏\n");
    printf("  11  ---------------------------------------   退出\n\n");
    printf("------------------------------------------------------------------\n");
    printf("请选择您需要的操作:");
}

选择查找方式,包含了按内容查找和按序号查找。

LNode *SelectFind(){//选择查找方式
    LNode *p;
    int i=0,j;
    printf("请选择您需要查找的方式:\n");
    printf("1.按序号查找     2.按内容查找\n");
    printf("您的选择是:");

    while((i!=1)&&(i!=2)){
        scanf("%d",&i);
        switch(i){
            case 1:
                printf("请输入需要查找的位置:");
                scanf("%d",&j);
                p=GetLinkList(j);
                break;
            case 2:
                p=LocationLinkList();
                break;
            default:
                printf("输入有误,请重新输入:");
                break;
        }
    }
    return p;
}

检查输入数据是否为11位整数的电话号码

void CheckLinkList(){
    LNode *s;
  while(1){
            int j;
            scanf("%s",s->data.number);
            if(strlen(s->data.number)==11)
            {
                for(j=0;j<strlen(s->data.number);j++)
                    if(!isdigit(s->data.number[j]))//判断是否在0-9之间
                        break;
                if(j==strlen(s->data.number))
                    break;
            }
            if(strlen(s->data.number)!=11 || j!= strlen(s->data.number))
            printf("输入有误,请重新输入号码:");
        }
}

主函数,对各个函数进行调用。

int main (){
    int n,i,length;
    LNode *p,*s,*q;
    L=(LinkList)malloc(sizeof(LNode));
    L->next=NULL;

    menuLinkList();
    while(scanf("%d",&n))
        switch(n){
            case 1:
                    CreateLinkList();
                    break;
            case 2:
                    CreateLinkList2();
                    break;
            case 3:
                    InsertLinkList();
                    break;
            case 4:
                    DeleteLinkList();
                    break;
            case 5:
                    p=SelectFind();
                    if(p==NULL)
                        printf("未找到此联系人!");
                    else{
                        printf("该联系人已找到.....!\n");
                        printf("%s\t%s\n",p->data.name,p->data.number);
                    }
                    printf("请选择你的操作:");
                    break;

            case 6:
                    ChargeLinkLIst();
                    break;
            case 7:
                    length=LengthLinkList();
                    printf("此电话簿联系人个数为:");
                    printf("%d",length);
                    printf("请选择你的操作:");
                    break;
            case 8:
                    ReverseLinkList();
                    break;
            case 9:
                    PrintLinkList();
                    break;
            case 10:
                    system("CLS");
                    printf("清屏完成");
                    menuLinkList();
                    break;
            case 11:
                    exit(1);
            default: printf("输入有误,请重新输入:");
                    break;
        }
    return 0;
}
10-02 19:22