首页 > 其他分享 >数据结构

数据结构

时间:2022-09-21 11:11:11浏览次数:60  
标签:结点 ID next printf 数据结构 data ptr

设计并编程实现一个应用单链表存储结构的通信录管理系统。定义适当数据类型,设计并编写完成下列8项基本功能的C语言程序:

[root@huhy ~]# cat test.c
/*一、功能要求:
 1.添加 2.查找 3.删除 4.修改 */
/*二、包含信息
 每一个联系人包含编号、姓名、手机、qq等信息*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct TongXun{
        char ID[15];
        char name[12];
        char tel[15];
        char QQ[15];
}datatype;

typedef struct node{
        datatype data;
        struct node *next;
}Node, *LinkNode;

LinkNode head =NULL; //先确定头结点

/*功能函数*/
void Menu();                            //0.显示界面
void InitList();                        //1.通讯录的初始化***

                                                        //2.建立通讯录(单链表的建立)*******
void CreateList_Head();         //2.1头插法创建
int JudgeID(LinkNode ptr1,LinkNode ptr2);//2.11判断ID是否重复
void CreateList_Tail();         //2.2尾插法创建

void DelList();                 //3.删除数据(根据姓名删除) ********

void UpdateList();      //4.修改信息******

void SearchList();              //5.查找信息

                                                        //6.插入信息 ******
void InsertList_Pre();          //6.1前插法
void InputList(LinkNode ptr);                   //6.11输入指定结点指针相关信息
void InsertList_Back();         //6.2后插法


void TraverseList(); //7.遍历通讯录
void PrintList(LinkNode ptr); //7.1输出指定信息

void DestroyList();  //8.释放通讯录***

void save(LinkNode stu);        //9.用于将数组中的信息保存到文件中 (n个同学)
int NumList(LinkNode head);     //9.1 通过头指针,遍历单链表进行人数统计并返回

/*主控函数*/
int  main(void)
{
        int choice;

        while (1)
        {
                Menu();
                printf("请选择菜单:");
                scanf("%d", &choice);
                switch (choice)
                {
                    case 1:             //初始化通讯录
                                        InitList(); break;
                        case 2:         //建立通讯录
                                {
                                                int num;
                                                printf("请选择建立方式(1.头插法 2.尾插法):");
                                                scanf("%d", &num);   /****下边的大括号不可以省略 ****/
                                                if (num == 1)   //头插法
                                                {
                                                   CreateList_Head();  break;
                                                }

                                                if (num == 2)   //尾插法
                                                {
                                                        CreateList_Tail();  break;
                                                }


                                }

                        case 3:         //删除信息
                                        DelList(); break;

                        case 4:         //修改信息
                                        UpdateList(); break;

                        case 5:         //查找信息
                                        SearchList(); break;

                        case 6:         //添加信息
                       {

                                        int num;
                                        printf("请选择插入方式(1.前插法 2.尾插法):");
                                        scanf("%d", &num);
                                        if (num == 1) //头插法
                                        {
                                                InsertList_Pre(); break;
                                        }
                                        if (num == 2) //尾插法
                                        {
                                            InsertList_Back(); break;
                                        }


                      }


                        case 7:         //遍历通讯录
                                        TraverseList(); break;

                        case 8: //释放通讯录
                                        DestroyList(); break;


                    default: return 0;
                }
        }
        return 0;
}

/*0.显示界面*/
void Menu()
{
        printf("\t\t\t****************************************************\n");
        printf("\t\t\t1.初始化通讯录                          2.建立通讯录\n");
        printf("\t\t\t3.删除联系人                            4.修改联系人\n");
        printf("\t\t\t5.查找联系人                            6.添加联系人\n");
        printf("\t\t\t7.输出通讯录                            8.释放通讯录\n");
        printf("\t\t\t***************其他按键视为退出**********************\n");
}
/*1.通讯录的初始化*/
//(建立头结点)
void InitList()
{
     head= (LinkNode)malloc(sizeof(Node));
     head->next = NULL;
     printf("初始化成功!\n");
     save(head);
}



/*2.建立通讯录(单链表的建立)*/
//2.1插入数据,建立通讯录(头插法)
//首先建立新结点,为其动态开辟内存空间
//接着为该结点的data域存入数据
//然后经典头插代码(为让新结点插入头结点和首元结点之间)
//先让新结点的指针域指向原首元结点;然后让头结点的指针域指向该新结点
//就是通过结点间的指针进行连接/相关联
void CreateList_Head()
{
    LinkNode ptr;
    LinkNode ptr2;
    int item=1;         //用来控制循环(决定是否继续录入信息)
    int n;

    //需要实现:循环直至自行决定,不继续建立新的联系人
    //另写函数2.11,实现排除输入ID重复
    while(item!=0)
    {
        ptr = (LinkNode)malloc(sizeof(Node));//动态分配内存(新结点)


        printf("请输入通讯信息:\n");
        printf("请输入姓名:");
        scanf("%s",&(ptr->data.ID));
                ptr2 = head->next;
        n = JudgeID(ptr,ptr2); //ID有重复n=1;
        //调用函数2.11进行判断ID是否重复

        while(n==1)
        {
                        printf("姓名已存在请重新输入:\n");
                        scanf("%s",&(ptr->data.ID));
                        n = JudgeID(ptr,ptr2); //ID有重复n=1;
                }

                    printf("请输入电话:\n");
                    scanf("%s",&(ptr->data.name));
                    printf("请输入QQ:\n");
                    scanf("%s",&(ptr->data.tel));
                    printf("请输入住址:\n");
                    scanf("%s",&(ptr->data.QQ));

                    //头插法的经典代码
                    ptr->next = head->next;
                    head->next = ptr;
                    printf("是否继续录入,继续:1,退出:0\n");
                    scanf("%d",&item);

        }
        save(head);
   return ;
}
//2.11实现排除输入ID重复
//传入需要比对的结点,遍历单链表逐个比对ID
//要和首元结点的指针域指向的结点比较(次首元结点),就是新结点的指针域所指结点
//如果有重复返回 1,否则返回0;
int JudgeID(LinkNode ptr1,LinkNode ptr2)
{
        while(ptr2!=NULL)
        {
          if(strcmp(ptr1->data.ID,ptr2->data.ID)==0)
             return 1;
          else
            ptr2 = ptr2->next;
        }
        return 0;
}

/*
   2.建立通讯录(单链表的建立)
//2.1插入数据,建立通讯录(头插法)
void CreateList_Head()
{
        List *node; //插入节点
        int count = 0;
        int flag = 1;//用于判断是否继续输入下一条记录
        while (flag)
        {
                count++;
                node= (List *)malloc(sizeof(List));  //为新建的结点开辟内存
                printf("插入第%d条记录:\n", count);
                printf("ID:");
                scanf("%s", &(node->data.ID));

                //判断ID是否重复
                List *p = L->next;
                while (p)
                {
                        if (strcmp(p->data.ID, node->data.ID) == 0)
                        {
                                printf("ID重复,请重新输入!\n");
                                printf("ID:");
                                scanf("%s", &(node->data.ID));
                        }
                        else
                                p = p->next;
                }
                printf("姓名:");
                scanf("%s", &(node->data.name));
                printf("电话:");
                scanf("%s", &(node->data.tel));
                printf("QQ:");
                scanf("%s", &(node->data.QQ));

                //头插法的核心 代码
                node->next = L->next; //对于新建立的结点,先确定其指针域,再确定头指针的指向
                L->next = node;
                printf("是否继续录入(1.继续 0.完成录入):");
                scanf("%d", &flag);
                if (flag == 0)
                        break;
        }
}
*/
/*2.2尾插法创建 */
//首先先建立一个新结点和一个尾结点rear(一直指向尾结点)
//依旧需要为新结点的data域赋值
//依旧让rear指向头结点
//但是尾插法核心仍然是:
//先让新结点作为rear的后继结点,然后让rear还指向尾结点;
void CreateList_Tail()
{
        LinkNode  ptr, rear=head;       //定义新结点和尾节点
        LinkNode  ptr2;
    int item = 1; //用来判断循环是否继续
    int n;
    while(item ==1 )
        {
                ptr = (LinkNode)malloc(sizeof(Node));//动态分配内存(新结点)
                printf("请输入通讯信息:\n");
        printf("请输入姓名:");
        scanf("%s",&(ptr->data.ID));
                  ptr2 = head->next;
            n = JudgeID(ptr,ptr2); //ID有重复n=1;
        //调用函数2.11进行判断ID是否重复

        while(n==1)             //如果加入的ID与之前重复,便一直循环重新输入
        {
                        printf("姓名已存在请重新输入:\n");
                        scanf("%s",&(ptr->data.ID));
                        n = JudgeID(ptr,ptr2); //ID有重复n=1;
                }
        printf("请输入电话:\n");
                scanf("%s",&(ptr->data.name));
                printf("请输入QQ:\n");
                scanf("%s",&(ptr->data.tel));
                printf("请输入住址:\n");
                scanf("%s",&(ptr->data.QQ));
        //尾插法的核心
                  rear->next =ptr;
                  ptr->next = NULL;
                  rear = ptr;

                printf("是否继续录入,继续:1,退出:0\n");
                scanf("%d",&item);
        }
        return ;
}

/*3.删除数据(根据姓名删除)
void DelList()
{
        LinkNode p = head->next;
        LinkNode q = head;
        char ID[10];
        printf("请输入要删除的ID:");
        scanf("%s", &ID);
        while (p && strcmp(p->data.ID, ID) != 0)//找到ID一样的,让P指向该结点
        {
                p = p->next;
                q = q->next;
        }
        if (p!= NULL)
        {
                q->next = p->next;
                printf("删除成功!\n");
                printf("被删除数据的信息为:\n");
                printf("ID:%s\n", p->data.ID);
                printf("姓名:%s\n", p->data.name);
                printf("电话:%s\n", p->data.tel);
                printf("QQ:%s\n", p->data.QQ);
                free(p);
        }
        else
        {
                printf("通讯录中不存在此人信息!\n");
        }
}
*/
/*3.删除数据(根据姓名删除)*/
//关键点:单链表所有结点间通过结点指针的指向来联系
//首先明确两个结点指针:p,q
//分别用来 使整个单链表联系;找到需要删除信息的结点
//然后需要保证-->单链表的完整连接性,
//最后释放-->需要删除的结点信息
void DelList()
{
   LinkNode p, q;
   p = head;
   q = head->next;
   char str[20];
   printf("请输入需要删除姓名:\n");
   scanf("%s",&str);
   //可能一开始就是空链表,或者遍历到最后(通过指针q来判断)
   while(q!=NULL && strcmp(q->data.ID,str)!=0) //遍历单链表,让结点指针q指向需要删除的结点
   {
          q = q->next;
          p = p->next;
   }

   if(q==NULL)//遍历单链表找不到该信息
   {
                printf("该信息不存在\n");
   }
   else
   {
           p->next = q->next;   //让p在单链表中保证其完整性
           printf("该信息如下:\n");
           printf("姓名为:%s\n",q->data.ID);
           printf("电话为:%s\n",q->data.name);
           printf("QQ号为:%s\n",q->data.tel);
           printf("住址为:%s\n",q->data.QQ);

           printf("通讯信息删除成功\n");
             free(q);
   }
   save(head);

}

/*4.修改信息*/
//先定义一个结点指针,让它指向首元结点
//进行遍历,与输入的ID进行比较,找到该信息所在结点
//然后进行(循环)修改信息:1.姓名 2.手机号 3.QQ号
void UpdateList()
{
        LinkNode ptr = head->next;
        int item=1,n=0;  //item控制是否继续修改信息
                                        //n用来判断是否修改该信息
        char str[20];
        printf("请输入需要修改的姓名:\n");
        scanf("%s",&str);
        while(ptr!=NULL&&strcmp(ptr->data.ID,str)!=0)//遍历单链表,找和所输入ID一致的结点
        {
                ptr = ptr->next;
        }
        if(ptr==NULL)
        {
                 printf("该信息不存在\n");
                 return ;
        }
          //能够找到该信息,就会进行修改
        while(item==1) //item为1表示继续修改信息
        {
                printf("是否要修改电话:(是:1 否:0)\n");
                   if(scanf("%d",&n),n==1)
                     scanf("%s",&ptr->data.name);
                printf("是否要修改QQ号:(是:1 否:0)\n");
                        if(scanf("%d",&n),n==1)
                      scanf("%s",&ptr->data.tel);
                printf("是否要修改住址:(是:1 否:0)\n");
                        if(scanf("%d",&n),n==1)
                      scanf("%s",&ptr->data.QQ);
                printf("是否需要重新修改信息:(是:1 否:0)\n");
                scanf("%d",&item);
        }
        save(head);
}

/*5.查找指定ID信息*/
//先定义一个结点指针,指向首元结点
//接着进行遍历单链表,找该信息所在结点
//然后输出该信息
void SearchList()
{
        LinkNode ptr = head->next;
        char str[20];
        printf("请输入需要查找的姓名:\n");
        scanf("%s",&str);
        while(ptr!=NULL&&strcmp(ptr->data.ID,str)!=0)//遍历单链表,找和所输入ID一致的结点
        {
                ptr = ptr->next;
        }
        if(ptr==NULL)
        {
                 printf("该信息不存在\n");
                 return ;
        }

        //如果找到该信息,就会输出

        printf("该通讯信息如下:\n");
        PrintList(ptr);

}


/*5.插入数据(前插法)
void InsertList_Pre()
{
   LinkNode p, q, r, node;
        p = head->next;
        q = head;
        char ID[10];
        printf("请输入要插入的位置(输入该位置的ID):");
        scanf("%s", &ID);//结点指针p用来遍历指向 所要添加的位置
        while (p && strcmp(p->data.ID, ID) != 0)
        {
                p = p->next;
                q = q->next;
        }

        if (p != NULL)
        {
                //给新节点分配空间
                node = (LinkNode)malloc(sizeof(Node));
                //录入新节点数据
                printf("请输入新节点信息:\n");
           judge:
                        printf("ID:");
                        scanf("%s", &(node->data.ID));
                        //判断ID是否重复
                    r = head->next;
                    while (r && strcmp(r->data.ID, node->data.ID) != 0)
                        {
                                r = r->next;
                    }
          if (r != NULL)
          {
                  printf("ID重复,请重新输入!\n");
                  //free(r); 这里不能free(r),如果释放r,会失去r的下一个节点的信息,链表会被破坏
                  goto judge;
          }
          printf("姓名:");
          scanf("%s", &(node->data.name));
          printf("电话:");
          scanf("%s", &(node->data.tel));
          printf("QQ:");
          scanf("%s", &(node->data.QQ));
        }



        else
        {
                //如果没有该ID
                int choice1;
                printf("通讯录中未找到该ID,是否使用默认方式将新节点插入到最后(1.是 0.否):");
                scanf("%d", &choice1);
                if (choice1 == 1)
                {
                        //给新节点分配空间
                        node = (LinkNode)malloc(sizeof(Node));
                        //给新节点输入数据
                        printf("请输入新节点信息:\n");
                judge1:
                        printf("ID:");
                        scanf("%s", &(node->data.ID));
                        //判断ID是否重复
                        r = head->next;
                        while (r && strcmp(r->data.ID, node->data.ID) != 0)
                        {
                                r = r->next;
                        }
                        if (r != NULL) //ID重复
                        {
                                printf("ID重复,请重新输入!\n");
                                goto judge1;
                        }
                        printf("姓名:");
                        scanf("%s", &(node->data.name));
                        printf("电话:");
                        scanf("%s", &(node->data.tel));
                        printf("QQ:");
                        scanf("%s", &(node->data.QQ));
                }
                else
                        return;
        }
        node->next = q->next;
        q->next = node;
        printf("插入成功!\n");
}
*/
/*6.1仿头插法-->前插法(添加信息到指定位置)*/
//首先输入ID,确定新结点插入位置 (让结点指针p指向该位置)
//接着为新结点 ptr 开辟内存并赋值
//然后就是模仿-->经典的头插法
//建立链表时,(头插法建立)已经写好的函数进行封装,接着在该函数进行调用;
void InsertList_Pre()
{
         LinkNode p,L,ptr;        //结点指针L伴随着p一起移动
         char str[20];
         L = head;
         p = head->next;

         //需要输入ID,遍历单链表,将p指向该结点

         //情况1:如果p不是空指针,最后进行仿头指针的经典代码(将指针L假想成头指针)
         //情况2:如果p是空指针,此时便是头结点
         //可以为新结点 ptr 依次输入信息(记得查重复ID)
         //因此两种情可以用一个经典代码(将结点指针L,假想为头结点)进行插入添加

        printf("请输入姓名(新信息会插入到该信息前):\n");
         scanf("%s",&str);
         while(p!=NULL && strcmp(p->data.ID,str)!=0)    //逻辑符号的使用
         {
                p = p->next;
                L = L->next;
         }

         if(p==NULL)
         {
                printf("所输入的姓名不存在\n");
                return;
         }


        //为新结点开辟内存并赋值
          ptr =(LinkNode)malloc(sizeof(Node));
          //函数InputList()   为指定结点指针-->输入相关信息
           InputList(ptr);

        //经典头插法核心代码
           //仿头插法(将 L的指向看作头结点,p的指向看作首元结点)
           ptr->next = L->next;
           L->next =ptr;
           printf("信息插入成功\n");
           save(head);
}
/*6.11输入指定结点指针相关信息*/
//功能中实现防输入重复ID
void InputList(LinkNode ptr)
{
        int n=0;
        printf("请输入通讯信息:\n");
    printf("请输入姓名:");
    scanf("%s",&(ptr->data.ID));
    LinkNode ptr2 = head->next;
      n = JudgeID(ptr,ptr2); //ID有重复n=1;
        //调用函数2.11进行判断ID是否重复

    while(n==1)         //如果加入的ID与之前重复,便一直循环重新输入
    {
                printf("姓名已存在请重新输入:\n");
                scanf("%s",&(ptr->data.ID));
                n = JudgeID(ptr,ptr2); //ID有重复n=1;
        }

                    printf("请输入电话:\n");
                    scanf("%s",&(ptr->data.name));
                    printf("请输入QQ号:\n");
                    scanf("%s",&(ptr->data.tel));
                    printf("请输入住址:\n");
                    scanf("%s",&(ptr->data.QQ));

}
/*6.2仿尾插法-->后插法(添加信息到指定位置)*/
//首先让指针结点遍历单链表,来找指定ID的位置
//然后创建新结点,为其开辟动态内存并赋值
//最后仿尾插法运用经典代码

//结点指针 p,L;分别用来作为当前遍历的首元结点,总是指向当前的尾结点
//就是用指针p来遍历单链表
//当p为NULL时,即没有找到指定ID,将此时L作为尾结点进行处理
//当p不是NULL,即找到指定ID,将此时p作为尾结点进行处理
void InsertList_Back()
{
        LinkNode p,L,ptr;         //结点指针L伴随着p一起移动
        LinkNode node;  //暂存所指结点后的结点(以防出现单链表中途插入新信息)
        char str[20];
        L = head;
        p = head->next;

        printf("请输入姓名(新信息会插入到该信息前):\n");
        scanf("%s",&str);
        while(p!=NULL && strcmp(p->data.ID,str)!=0)     //逻辑符号的使用
        {
                p = p->next;
                L = L->next;
        }


        if(p == NULL)
        {
          printf("所输入的姓名不存在\n");
           return;
         /*
          L->next = ptr;
          L = ptr;
          ptr = NULL;
        */
        }

                //为新结点开辟内存并赋值
          ptr =(LinkNode)malloc(sizeof(Node));
        //函数InputList()   为指定结点指针-->输入相关信息
           InputList(ptr);


           //暂存 所指结点后的结点(以防出现单链表中途插入新信息)
            node = p->next;

           //经典尾插法的核心代码
           p->next = ptr;
           p = ptr;

           //保证插入后单链表的完整性
           ptr->next = node;
          // ptr = NULL;   //仿尾插法,可能所要插入的ID不在单链表的最后

        save(head);
}


/*7.遍历通讯录*/
void TraverseList()
{
        LinkNode p;
        if (head == NULL)
        {
                printf("通讯录为空!\n");
                return;
        }
        else
        {
                p = head->next;
                printf("通讯录中全部信息如下:\n");
                while (p)
                {
                        PrintList(p);
                        p = p->next;
                }
        }
}

//7.1输出指定信息
void PrintList(LinkNode ptr)
{
    printf("姓名:%-15s\t", ptr->data.ID);
        printf("电话:%-10s\t", ptr->data.name);
        printf("QQ:%-15s\t", ptr->data.tel);
        printf("住址:%-15s\n", ptr->data.QQ);

}
/*8.释放通讯录*/
//需要释放内存后,接着把指针指向NULL
//释放头结点,首元结点和遍历单链表所指向的结点
//先定义两个结点指针 p,t;
//分别用来遍历单链表,暂时指向所遍历之处的结点
void DestroyList()
{
        LinkNode p, t;
        p = head->next;
        while(p!= NULL) //遍历单链表,进行内存释放,数据置空
        {
                t = p;
                free(t);
                t = NULL;
                p = p->next ;
        }
        //遍历完单链表,此时p为空指针
        free(p);
        free(head);
        head = NULL;

        printf("单链表清空成功\n");
         save(head);
}

/* 9.用于将数组中的信息保存到文件中 (n个同学)*/
//调用fwrite()函数 ,将数组中的信息存入文件中
//了解exit()函数 ,用来终止正在执行的程序
void save(LinkNode stu)
{
        FILE *fp;
        int n;
        n = NumList(stu);
        if((fp = fopen("D:\\student1.txt","w")) == NULL)
        {
                printf("打开文件失败\n");
                exit(0);
        }

        fwrite(stu , n*sizeof(Node) , 1,fp); //一个学生信息,用一个结构体数组存储
        fclose(fp);
}
//9.1 通过头指针,遍历单链表进行人数统计并返回
int NumList(LinkNode head)
{
        int num=0;
        LinkNode L;
        L = head->next;
        while(L!=NULL)
        {
           num++;
           L =L->next;
        }

        return num;
}

标签:结点,ID,next,printf,数据结构,data,ptr
From: https://www.cnblogs.com/hwiung/p/16714883.html

相关文章

  • Java软件结构与数据结构 pdf
    高清扫描版下载链接:https://pan.baidu.com/s/1-aD4I1Fy1Q2j0DGbu-44ig点击这里获取提取码 ......
  • TMS320C28x数据结构
    来自《TMS320C28xOptimizingC_C++CompilerUser'sGuide》的章节6.4,文档编号:SPRU514R  ......
  • 数据结构算法与应用:C++语言描述(第2章 程序性能)
    目录2.1引言2.2空间复杂性(spaceComplexity)\(S_p(n)\)2.2.1空间复杂性的组成2.2.2举例2.3时间复杂性(timecomplexity)\(T(n)\)2.3.1时间复杂性的组成2.3.2操作计......
  • 数据结构算法与应用:C++语言描述(第2章 程序性能)
    目录2.1引言2.2空间复杂性(spaceComplexity)\(S_p(n)\)2.2.1空间复杂性的组成2.2.2举例2.3时间复杂性(timecomplexity)\(T(n)\)2.3.1时间复杂性的组成2.3.2操作计......
  • Java面向对象数据结构完全学习教程 pdf
    高清扫描版下载链接:https://pan.baidu.com/s/1m6FOQFqsjqYSbKXKs8zHjQ点击这里获取提取码 ......
  • 数据结构与算法【Java】07---树结构基础部分
    前言数据data结构(structure)是一门研究组织数据方式的学科,有了编程语言也就有了数据结构.学好数据结构才可以编写出更加漂亮,更加有效率的代码。要学习好数据结构就......
  • redis底层数据结构
    跳跃列表是一种数据结构。它允许快速查询一个有序连续元素的数据链表。跳跃列表的平均查找和插入时间复杂度都是O(logn),优于普通队列的O(n)。为什么要使用跳表?数组......
  • 数据结构实验(三)线性表的操作与应用
    6-1顺序表实现intListLength(SqListL){returnL.length;}intLocateElem(SqListL,ElemTypee,Status(*compare)(ElemType,ElemType)){//虽然说......
  • 线性结构 | 数据结构
    线性数据结构队列什么是队列?先进先出,先来的先购买可以基于数组实现:有界队列,队列的大小有限,满了就会拒绝请求可以基于链表来实现:无界队列,可能导出过多的请求排队等待......
  • 数据结构一: golang 单向队列
    队列是什么,如何理解队列?队列一般称queue,是一个有序列表队列一般的原则为:先进先出【谁先来,谁先走】队列一般的场景可以想象:银行取现排队,移动营业厅排队,买咖啡排队等例......