通讯录 双向链表
c语言实现通讯录管理系统(用链表实现)

c语⾔实现通讯录管理系统(⽤链表实现)题⽬:通讯录(通过链表实现)设计并实现⼀个简易的通讯录软件,管理个⼈通讯记录。
⼀条通讯记录可包括:姓名、⼯作单位、⼿机、住宅电话、E-Mail、家庭住址等(可⾃⾏增删,但不可过少)。
该系统应实现以下基本功能:(1)增加新的通讯记录。
(2)删除已有的通讯记录。
(3)修改已有的通讯记录。
(4)浏览全部或指定(如指定姓名、⼯作单位等)的通讯记录。
(5)合理组织排列各项功能,界⾯可使⽤键盘操作。
(6)以⽂件的形式存储数据。
说明:⼤⼀时的c语⾔课设,⽤链表实现⼀个通讯录管理系统,为了美观好看,花了很多时间调整齐度,记录⼀下⼤⼀时的作业。
其主要功能是对通讯录可输⼊,显⽰,插⼊,删除,最难是可保存,这个学⽂件的时候不怎么会。
内容我⾃⼰弄了7个,名字,性别,⼯作单位,⼿机,住宅电话,E-Mail,家庭住址(其他太多其实都是⼀样的,就懒得加了)。
主要运⽤到对指针中的链表的功能和使⽤要⽐较扎实,分部列写就可以了。
实现图⽚:附上代码:1 #include <stdio.h>2 #include <string.h>3 #include <stdlib.h>4 typedef struct student5 {6char name[20];//名字7char wm[20];//性别8char work[100];//⼯作单位9char stel[20];//⼿机10char htel[20];//住宅号码11char mail[20];//E-Mail12char home[100];//家庭住址13struct student *next;14 }stu;15 stu *head;//头指针16void screen()//主菜单17 {18 printf("\n=======================================================\n");19 printf(" 欢迎来到通讯录管理系统\n\n");20 printf(" 1.输⼊数据 2.显⽰数据\n");21 printf(" 3.插⼊数据 4.删除数据\n");22 printf(" 5.查看数据 6.修改数据\n");23 printf(" 7.保存数据 8.返回主菜单\n");24 printf("\n~~~~~~输~~~~~~⼊~~~~~~9~~~~~~退~~~~~~出~~~~~~程~~~~~~序\n");25 }26void input()//输⼊数据27 {28int ans;//判断是否继续输⼊29 stu *p1,*p2;30 p1=(stu *)malloc(sizeof(stu));//申请内存来⽤31if(p1!=NULL)32 {33 printf("========输⼊数据========\n");34 head=p1;35while(1)36 {37 printf("名字:");38 scanf("%s",&p1->name);39 printf("性别:");40 scanf("%s",&p1->wm);41 printf("⼯作单位:");42 scanf("%s",&p1->work);43 printf("⼿机:");44 scanf("%s",&p1->stel);45 printf("住宅号码:");46 scanf("%s",&p1->htel);47 printf("E-Mail:");48 scanf("%s",&p1->mail);49 printf("家庭地址:");50 scanf("%s",&p1->home);51 printf("===================================\n");52 p2=p1;53 p1=(stu *)malloc(sizeof(stu));//申请下⼀个要⽤的空间54if(p1!=NULL)55 p2->next=p1;56 printf("请选择是否继续输⼊:1.继续 2.退出\n请选择:");//⽤户选择57 scanf("%d",&ans);58if(ans==1)//继续59continue;60else//退出61 {62 printf("========输⼊完毕========\n");63 p2->next=NULL;64free(p1);//将申请的的⽆⽤内存释放65break;66 }67 }68 }69 }70void look(stu *p1)//显⽰数据71 {72 printf("========显⽰数据========\n");73while(p1!=NULL)74 {75 printf("名字:%s\n",p1->name);76 printf("性别:%s\t",p1->wm);77 printf("⼯作单位:%s\t",p1->work);78 printf("⼿机:%s\t",p1->stel);79 printf("住宅号码:%s\t",p1->htel);80 printf("E-Mail:%s\t",p1->mail);81 printf("家庭住址:%s\n",p1->home);82 printf("=====================================\n");83 p1=p1->next;84 }85 printf("========显⽰完毕========\n");86 }87void insert()//插⼊数据88 {89int ans;//选择插⼊位置90char name[20];//插⼊者的名字91 printf("========插⼊数据========\n");92 stu *p1,*p2,*p3;93 p1=head;94 p3=(stu *)malloc(sizeof(stu));//申请内存95 p3->next=NULL;96 printf("请输⼊插⼊者的数据:\n");97 printf("名字:");98 scanf("%s",&p3->name);99 printf("性别:");100 scanf("%s",&p3->wm);101 printf("⼯作单位:");102 scanf("%s",&p3->work);103 printf("⼿机:");104 scanf("%s",&p3->stel);105 printf("住宅号码:");106 scanf("%s",&p3->htel);107 printf("E-Mail:");108 scanf("%s",&p3->mail);109 printf("家庭地址:");110 scanf("%s",&p3->home);111 printf("请选择插⼊位置:1.⾸位置插⼊ 2.尾部插⼊ 3.插到某⼈前⾯\n请选择:");112 scanf("%d",&ans);113switch(ans)114 {115case1://放到头指针116 p3->next=p1;117 head=p3;118break;119case2://放到尾部120while(p1->next!=NULL)121 p1=p1->next;122 p1->next=p3;123break;124case3://放到某⼈前⾯125 printf("请输⼊插到谁前⾯名字:");126 scanf("%s",name);127while(strcmp(name,p1->name)!=0)128 {129 p2=p1;130 p1=p1->next;131 }132 p2->next=p3;133 p3->next=p1;134break;135 }136 printf("========插⼊成功========\n");137 }138void deleted()//删除数据139 {140 stu *p1,*p2;141char name[20];//删除者名字142 printf("========删除数据========\n");143 printf("请输⼊要删除者的名字:");144 scanf("%s",name);145 p1=head;146if(head==NULL)//通讯录已经没数据了147 {148 printf("通讯录⾥什么也没有了。
双链表—电话簿管理

#include <fstream>#include <iostream>#include <iomanip>#include <string>#include <cstdlib>using namespace std;struct friend_node{char first_name[15];char last_name[20];char phone_num[12];friend_node* next;friend_node* prior;};friend_node* head_ptr=NULL;friend_node* tail_ptr=NULL;friend_node* current_ptr; //当前指针:指向链表中某个正在被处理的结点class Record{public://struct friend_node;//void Userchoice(int choice);void InsertRecord(); // 插入记录void InsertNode(friend_node* new_ptr); //插入结点,分3种情况,头部,尾部,中间void InsertNodeAtHead(friend_node* new_ptr);void InsertNodeAtEnd(friend_node* new_ptr);void ShowList();void SearchByLastName();void DeleteRecord(); // 删除记录int VerifyDelete();void DeleteNode(); //删除结点,分3情况,删除头部,尾部,中间void DeleteNodeAtHead();void DeleteNodeAtEnd();void DeleteNodeAtMiddle();void SaveFile();void LoadFile();void DeleteList();void Showmenu();void ModifyRecord();};void Record::InsertRecord() //插入记录,分3种情况,头部,尾部,中间{friend_node* new_ptr;new_ptr=new friend_node;if(new_ptr!=NULL){cout<<"名字:\n";cin>>new_ptr->first_name;cout<<"姓氏:\n";cin>>new_ptr->last_name;cout<<"电话号码:\n";cin>>new_ptr->phone_num;InsertNode(new_ptr);cout<<"是否继续添加信息?(y/n)\n";char input;cin>>input;if('y'==input||'Y'==input)InsertRecord();else if('n'==input||'N'==input)return;}elsecout<<"----------\n";}void Record::InsertNodeAtHead(friend_node* new_ptr){new_ptr->next=head_ptr; //首先new_ptr的前后都得有指向new_ptr->prior=tail_ptr;head_ptr->prior=new_ptr;tail_ptr->next=new_ptr;head_ptr=new_ptr;}void Record::InsertNodeAtEnd(friend_node* new_ptr){new_ptr->prior=tail_ptr;new_ptr->next=head_ptr;tail_ptr->next=new_ptr;head_ptr->prior=new_ptr;tail_ptr=new_ptr;}void Record::InsertNode(friend_node* new_ptr){//system("cls");friend_node* temp_ptr;//1.双向链表为空if(head_ptr==NULL){new_ptr->next=new_ptr;new_ptr->prior=new_ptr;head_ptr=new_ptr;tail_ptr=new_ptr;return;}//2.链表中只有一个结点if(head_ptr->next=head_ptr){if(strcmp(new_ptr->last_name,head_ptr->last_name)<0) //链表头部{InsertNodeAtHead(new_ptr);}else //链表尾部{InsertNodeAtEnd(new_ptr);}return;}//3.如果链表中不是只有一个结点if(head_ptr->next!=head_ptr){current_ptr=head_ptr->next;while((strcmp(new_ptr->last_name,current_ptr->last_name)>0)&&(current_ptr!=head_ ptr))current_ptr=current_ptr->next;if(current_ptr==head_ptr)//指向当前结点的指针current_ptr指向头结点时,即查找完整个链表后退出//则插入链表尾部{new_ptr->prior=tail_ptr;new_ptr->next=head_ptr;tail_ptr->next=new_ptr;head_ptr->prior=new_ptr;tail_ptr=new_ptr;}else//如果查找完整个链表,并且满足排序条件退出,欲插入的结点应插到current_ptr之前 {temp_ptr=current_ptr->prior;new_ptr->next=current_ptr;new_ptr->prior=temp_ptr;current_ptr->prior=new_ptr;temp_ptr->next=new_ptr;//插入很简单,即new_ptr的前后得都有指向,而后前后指针都有指向new_ptr}return;}}//画好图就ok了。
链表通讯录课程设计

链表通讯录课程设计一、教学目标本课程的目标是让学生掌握链表在通讯录管理中的应用。
具体来说,知识目标包括理解链表的基本概念、结构及其在通讯录中的作用;技能目标则是培养学生运用链表进行通讯录数据管理的能力,包括创建、删除、查找和修改通讯录信息;情感态度价值观目标则是培养学生对计算机科学的好奇心、探索精神和责任感。
二、教学内容本课程的教学内容主要包括链表的基本概念、结构及其在通讯录管理中的应用。
具体安排如下:1.第一课时:链表的基本概念和结构。
介绍链表的定义、特点及其与数组的区别。
2.第二课时:链表的创建与删除。
讲解如何创建一个链表、如何删除链表中的节点以及如何释放链表内存。
3.第三课时:链表的查找与修改。
教授如何查找链表中的节点、如何修改链表中的节点数据以及如何实现链表的排序。
4.第四课时:链表在通讯录中的应用。
结合实际案例,讲解如何使用链表管理通讯录信息,包括增加、删除、查找和修改通讯录条目。
三、教学方法为了激发学生的学习兴趣和主动性,本课程将采用多种教学方法。
主要包括:1.讲授法:用于讲解链表的基本概念、结构和通讯录管理的基本原理。
2.案例分析法:通过分析实际案例,让学生了解链表在通讯录中的应用。
3.实验法:让学生动手实践,实际操作链表的操作方法,提高其实际应用能力。
四、教学资源为了支持教学内容和教学方法的实施,丰富学生的学习体验,我们将准备以下教学资源:1.教材:《数据结构与算法》。
提供链表的基本概念、结构和算法。
2.多媒体资料:包括链表的动画演示、实际案例的视频讲解等,帮助学生更直观地理解链表的操作。
3.实验设备:提供计算机和编程环境,让学生可以实际操作链表的操作方法。
五、教学评估本课程的评估方式包括平时表现、作业和考试三个部分,以全面、客观、公正地评价学生的学习成果。
具体安排如下:1.平时表现:占比30%,通过课堂参与、提问、小组讨论等方式评估学生的学习态度和理解程度。
2.作业:占比30%,布置与课程内容相关的编程练习,评估学生的实际操作能力。
c语言双链表通讯录

c语言双链表通讯录题目三:通讯录系统1.实验目的和意义:利用c语言编写通讯录系统,使我们更加熟练的掌握c语言及软件开发的基本步骤,进一步理解并掌握结构体和双链表的使用,初步掌握文件的调用。
该课题设计对学生来说是对这一学期有关c语言学习的一个评估,是将c语言应用于生活中,提高学生的动手能力。
该课题有利于让学生将课本上学习的零散的知识融会贯通、综合运用、强化知识体2.实验内容:1、当启动通讯录管理系统时读取通讯录文件2、进入主功能菜单3、创建联系人列表并保存修改后的通讯录4、删除创建的联系人并保存修改后的通讯录5、打印出保存后的通讯录当未创建通讯录时提示用户创建新的通讯录6、根据用户输入的联系人的首字母查找符合条件的联系人7、退出通讯录管理系统3.小组成员分工:小组讨论算法:全体成员编写程序:樊义,高杰林,曹仲生调试程序:陈伟杰漏洞修复及报告设计:陈伟杰4.设计要点:建立结构体并创建链表,添加删除节点,字符串的匹配。
设计功能选择函数,5.源程序:#include "stdio.h"#include "stdlib.h"#include "string.h"typedef struct message{char name[30];char number[20];char email[30];char adress[100];char qq[120];struct message *proir;struct message *next;} mess;mess *head=NULL;mess *p[100];int man=0;/////////////////////////////////////////////////////////////////// /////////// char menu();void add();void del();char del_menu();void del_name();void del_adress();void del_number();void del_email();void del_qq();void find();char find_menu();void find_name();void find_adress();void find_number();void find_email();void find_qq();void print();char print_menu();void print_time();void print_word();void file_save();/////////////////////////////////////////////////////////////////// ///////// //////////////////////////////////主函数int main(){FILE *fp=fopen("1.txt","r+");if(fp==NULL)printf("通讯录为空!!\n");else{fseek(fp,0,2);if(ftell(fp)==0)printf("通讯录为空!\n");else{mess *p2,*tmp;rewind(fp);head=(mess *)malloc(sizeof(mess));head->next=NULL;p[0]=head;while(feof(fp)==0){p2=(mess *)malloc(sizeof(mess));fscanf(fp,"%s%s%s%s%s",p2->name,p2->adress,p2->numb er,p2->email,p2->qq);tmp=head;while(tmp->next!=NULL)tmp=tmp->next;tmp->next=p2;p2->next=NULL;p2->proir=tmp;man++;p[man]=p2;p[man+1]=NULL;}man--;p2->proir->next=NULL;printf("数据读取完毕!\n");int flag=fclose(fp);if(flag!=0){printf("关闭文件失败!");return 0;} }}start:char i;i=menu();switch(i){case '1':add();break;case '2':del();break;case '3':find();break;case '4':print();break;case '5':file_save();return 0;case '6':return 0;}goto start;}/////////////////////////////////////////////////////////////////// /////////////////////////////////////// //////主菜单char menu(){char i;printf("---------------功能菜单---------------\n");printf(" | 1.录入信息\t 2.删除信息|\n");printf(" | 3.查找信息\t 4.显示信息|\n");printf(" | 5.保存并退出 6.退出\t |\n");printf("--------------------------------------\n");while(1){printf("请输入功能编号:");scanf("%s",&i);if('0'<i&&i<'7')< p="">return i;elseprintf("无效指令!");}}/////////////////////////////////////////////////////////////////// /////////////////////////////////////// //////录入函数void add(){mess *p1;p1=(mess *)malloc(sizeof(mess));printf("请输入姓名:\n");scanf("%s",&p1->name);printf("请输入地址:\n");scanf("%s",&p1->adress);printf("请输入手机号码:\n"); scanf("%s",&p1->number);printf("请输入邮箱:\n");scanf("%s",&p1->email);printf("请输入qq号码:\n");scanf("%s",&p1->qq);if(head==NULL){head=(mess *)malloc(sizeof(mess)); head->next=p1;p1->next=NULL;p1->proir=head;p[0]=head;man++;p[man]=p1;p[man+1]=NULL;}else{mess *p2=head->next;while(p2->next!=NULL)p2=p2->next;p2->next=p1;p1->next=NULL;p1->proir=p2;man++;p[man]=p1;p[man+1]=NULL;}printf("添加成功!通讯录内现有%d个联系人\n是否继续录入信息........",man);char ch;done:scanf("%s",&ch);if(ch=='n');else if(ch=='y') add();else {printf("无效指令!请重新输入:");goto done;}}/////////////////////////////////////////////////////////////////// /////////////////////////////////////// ///删除函数void del(){char i=del_menu();switch(i){case '1':del_name();break;case '2':del_adress();break;case '3':del_number();break;case '4':del_email();break;case '5':del_qq();break;case '6':break;}}////////////////////char del_menu(){char i;printf("---------------删除菜单---------------\n"); printf(" | 1.按姓名删除\n | 2.按地址删除\n"); printf(" | 3.按手机号码删除\n | 4.按邮箱删除\n"); printf(" | 5.按qq号删除\n | 6.返回主菜单\n"); printf("--------------------------------------\n"); while(1){printf("请输入功能编号:");scanf("%s",&i);if('0'<i&&i<'7')< p="">return i;elseprintf("无效指令!");}}///////////////////void del_name(){if(man==0)printf("通讯录为空!\n\n");else{char ch[30];int i=1;mess *p1=head->next;printf("请输入被删用户的姓名:\n");scanf("%s",ch);while(p1!=NULL){if(strcmp(p1->name,ch)==0){while(p[i]!=p1)i++;while(p[i]!=NULL){p[i]=p[i+1];i++;}p1->proir->next=p1->next;if(p1->next!=NULL)p1->next->proir=p1->proir;printf("此用户信息已删除!");printf("是否继续删除........");man--;char tmp;done: scanf("%s",&tmp);if(tmp=='n')break;else if(tmp=='y') {del();break;}else {printf("无效指令!请重新输入:");goto done;} } p1=p1->next;}if(p1==NULL){printf("查无此人!\n");printf("是否继续删除........");char tmp;a: scanf("%s",&tmp);if(tmp=='n');else if(tmp=='y') del();else {printf("无效指令!请重新输入:");goto a;}}}}/////////////////////void del_adress(){if(man==0)printf("通讯录为空!\n\n");else{char ch[30];int i=1;mess *p1=head->next;printf("请输入被删用户的地址:\n"); scanf("%s",ch);while(p1!=NULL){if(strcmp(p1->adress,ch)==0) {while(p[i]!=p1)i++;while(p[i]!=NULL){p[i]=p[i+1];i++;}p1->proir->next=p1->next;if(p1->next!=NULL)p1->next->proir=p1->proir; printf("此用户信息已删除!");printf("是否继续删除........");man--;char tmp;done: scanf("%s",&tmp);if(tmp=='n')break;else if(tmp=='y') {del();break;}else {printf("无效指令!请重新输入:");goto done;} } p1=p1->next;}if(p1==NULL){printf("查无此人!\n");printf("是否继续删除........");char tmp;a: scanf("%s",&tmp);if(tmp=='n');else if(tmp=='y') del();else {printf("无效指令!请重新输入:");goto a;}}}}/////////////////////////////void del_number(){if(man==0)printf("通讯录为空!\n\n");else{char ch[30];int i=1;mess *p1=head->next;printf("请输入被删用户的电话号码:\n");scanf("%s",ch);while(p1!=NULL){if(strcmp(p1->number,ch)==0){while(p[i]!=p1)i++;while(p[i]!=NULL){p[i]=p[i+1];i++;}p1->proir->next=p1->next;if(p1->next!=NULL)p1->next->proir=p1->proir;printf("此用户信息已删除!");printf("是否继续删除........");man--;char tmp;done: scanf("%s",&tmp);if(tmp=='n')break;else if(tmp=='y') {del();break;}else {printf("无效指令!请重新输入:");goto done;} } p1=p1->next;}if(p1==NULL){printf("查无此人!\n");printf("是否继续删除........");char tmp;a: scanf("%s",&tmp);if(tmp=='n');else if(tmp=='y') del();else {printf("无效指令!请重新输入:");goto a;}}}}/////////////////////void del_email(){if(man==0)printf("通讯录为空!\n\n");else{char ch[30];int i=1;mess *p1=head->next;printf("请输入被删用户的邮箱:\n"); scanf("%s",ch);while(p1!=NULL){if(strcmp(p1->email,ch)==0) {while(p[i]!=p1)i++;while(p[i]!=NULL){p[i]=p[i+1];i++;}p1->proir->next=p1->next;if(p1->next!=NULL)p1->next->proir=p1->proir; printf("此用户信息已删除!");printf("是否继续删除........");</i&&i<'7')<></i&&i<'7')<>。
链表实现通讯录

#i n c l u d e<s t d i o.h>#include <malloc.h>#include <stdlib.h>#include <string.h>struct txl{char n[10];char name[10];char sex [10];char tele[12];char address[100];struct txl *next;};typedef struct txl TXL;typedef struct txl * link;enum result {exit_ok};void menu_select()//主菜单{printf(" 欢迎进入通讯录管理系统\n");printf("********************************\n");printf(" 1.联系人添加\n");printf(" 2.联系人删除\n");printf(" 3.联系人修改\n");printf(" 4.联系人查找\n");printf(" 5.联系人总览\n");printf(" 0.退出通讯录管理系统\n");printf("********************************\n");}void is_malloc_ok(link *new_node){if((*new_node) == NULL){printf("Malloc error!");exit(-1);}}void create_link(link *head){(*head) = (link)malloc(sizeof(TXL));is_malloc_ok(head);(*head)->next = NULL;}void create_new_node(link *new_node){int i;*new_node = (link)malloc(sizeof(TXL));is_malloc_ok(new_node);printf("请输入编号:\n");scanf("%s",&(*new_node)->n);printf("请输入姓名:\n");scanf("%s",&(*new_node)->name);printf("请输入性别:\n");scanf("%s",&(*new_node)->sex);printf("请输入联系电话:\n");scanf("%s",&(*new_node)->tele);printf("请输入家庭地址:\n");scanf("%s",&(*new_node)->address);printf("联系人添加成功!\n");}insert_new_node(link *new_node,link *head){(*new_node)->next = (*head)->next;(*head)->next = (*new_node);}void add_new_node(link *head){link new_node;create_new_node(&new_node);insert_new_node(&new_node,head);}void display(link *head){int i = 1;link p = NULL;if((*head)->next == NULL){printf("通讯录为空!\n");return;}else{p = (*head)->next;while(p != NULL){printf("第%d个联系人的信息如下:\n",i);printf("序号:%s\n",p->n);printf("姓名:%s\n",p->name);printf("性别:%s\n",p->sex);printf("联系电话:%s\n",p->tele);printf("家庭地址:%s\n\n\n",p->address);p = p->next;i++;}}}void find(link *head){char n1[10],name1[10],tele1[12],address1[100];int i;link xz = (*head)->next;printf("1.按编号查询\n");printf("2.按姓名查询\n");printf("3.按联系电话查询\n");printf("请输入您想选择的查询方式:\n");scanf("%d",&i);if(i == 1){printf("请输入您想查询的编号:\n");scanf("%s",n1);if(xz == NULL){printf("通讯录为空!\n");return;}while(xz !=NULL){if(strcmp(xz->n,n1) == 0){printf("您想查询的联系人的信息如下:\n");printf("编号:%s\n",xz->n);printf("姓名:%s\n",xz->name);printf("性别:%s\n",xz->sex);printf("联系电话:%s\n",xz->tele);printf("家庭地址:%s\n",xz->address);return;}elsexz = xz->next;}printf("通讯录中无此人!\n");}if(i == 2){printf("请输入您想查询的姓名:\n");scanf("%s",name1);if(xz == NULL){printf("通讯录为空!\n");return;}while(xz != NULL){if(strcmp(xz->name,name1) == 0){printf("您想查询的联系人的信息如下:\n");printf("编号:%s\n",xz->n);printf("姓名:%s\n",xz->name);printf("性别:%s\n",xz->sex);printf("联系电话:%s\n",xz->tele);printf("家庭地址:%s\n",xz->address);return;}elsexz = xz->next;}printf("通讯录中无此人!\n");return;}if(i == 3){printf("请输入您想查询的联系电话:\n");scanf("%s",tele1);if(xz == NULL){printf("通讯录为空!\n");return;}while(xz != NULL){if(strcmp(xz->tele,tele1) == 0){printf("您想查询的联系人的信息如下:\n");printf("编号:%s\n",xz->n);printf("姓名:%s\n",xz->name);printf("性别:%s\n",xz->sex);printf("联系电话:%s\n",xz->tele);printf("家庭地址:%s\n",xz->address);return;}elsexz = xz->next;}printf("通讯录中无此人!\n");return;}}void change(link *head){int a;link p = (*head)->next;char name1[10];char tele1[12];char address1[100];printf("请输入您想修改的联系人信息:\n");printf("1.姓名\n");printf("2.联系电话:\n");printf("3.家庭地址:\n");scanf("%d",&a);if(a == 1){printf("请输入原姓名:\n");scanf("%s",name1);while( p != NULL){if((strcmp(p->name,name1)) == 0){printf("请输入新的姓名:\n");scanf("%s",&p->name);printf("联系人修改成功!\n");return;}elsep = p->next;}printf("通讯录中没有此人!\n");return;}if(a == 2){printf("请输入原联系电话:\n");scanf("%s",tele1);while(p != NULL){if((strcmp(p->tele,tele1)) == 0){printf("请输入新的联系电话:\n");scanf("%s",&p->tele);printf("联系人修改成功!\n");return;}elsep = p->next;}printf("通讯录中没有此人!\n");}if(a == 3){printf("请输入原家庭地址:\n");scanf("%s",address1);while(p != NULL){if((strcmp(p->address,address1)) == 0){printf("请输入新的家庭地址:\n");scanf("%s",&p->address);printf("联系人修改成功!\n");return;}elsep = p->next;}printf("通讯录中没有此人!\n");}}void delete(link *head){link p1 = (*head);link p2 = (*head)->next;char name1[10];printf("请输入您要删除的联系人姓名:\n");scanf("%s",name1);if((*head)->next = NULL){printf("通讯录为空!\n");return;}while((strcmp(p2->name,name1) != 0)&&p2->next !=NULL) {p1 = p2;p2 = p2->next;}if(p2->next == NULL ){if(strcmp(p2->name,name1) == 0){p1->next = NULL;printf("该联系人已删除!\n");free(p2);}else{printf("通讯录中无此人!\n");}}else{p1->next = p2->next;free(p2);}}void exit_link(){printf("************************\n");printf(" 再见!\n");exit(exit_ok);}void switch_function(link *head){int num;scanf("%d",&num);switch(num){case 1:add_new_node(head); break;case 2:delete(head);break;case 3:change(head);break;case 4:find(head);break;case 5:display(head);break;case 0:exit_link();break;default:printf("该功能不存在,请重新输入!");break;}}int main(){link head = NULL;link new_node = NULL;create_link(&head);menu_select();while(1){printf("请输入您想要的功能:\n");switch_function(&head);}return 0;}。
通讯录管理系统 链表

一、通讯录管理系统1.题目要求通讯录一般包括通讯者的编号、姓名、性别、电话及地址等信息,设计一个通讯录要求实现通讯者的插入、查询、删除、更新、排序操作。
struct node{char num[5]; //编号char name[8]; //姓名char sex; //性别char tel[8]; //电话char address[100]; //地址};2.应用程序功能开始运行时界面如下:通讯录链表建立界面如下:通讯录链表插入界面如下:通讯录链表查询界面如下:按编号查询界面如下:按姓名查询编号如下:通讯录链表删除界面如下:通讯录链表输出界面如下:3.输入数据类型、格式和内容限制输入数据类型为字符型,但在输入过程中不可包含空格,如输入地址过程中不可出现空格!4.主要算法模块描述流程图:5.源程序代码#include<stdio.h>#include "iostream"int flag1=0;#include "string.h"#include "stdlib.h"#include "windows.h"using namespace std;typedef struct { //通讯录结点类型char num[5]; //编号char name[9]; //姓名char sex[3]; //性别char phone[13]; //电话char addr[31]; //地址} DataType;typedef struct node { //结点类型定义DataType data; //结点数据域struct node *next; //结点指针域} ListNode;typedef ListNode *LinkList;LinkList head;ListNode *p;LinkList CreateList(void);void InsertNode(LinkList head,ListNode *p);ListNode *ListFind(LinkList head);void DelNode(LinkList head);void PrintList(LinkList head);/*******尾插法建立带头结点的通讯录链表算法*******/LinkList CreateList(void){LinkList head=(ListNode *)malloc(sizeof(ListNode)); //申请头结点ListNode *p,*rear;char flag='y'; //int flag=0; //结束标志置0rear=head; //尾指针初始指向头结点while (flag=='y'){p=(ListNode *)malloc(sizeof(ListNode)); //申新结点printf("编号(4) 姓名(8) 性别电话(11) 地址(31)\n");printf("-----------------------------------------------\n");printf("\n添加的编号:\n");cin>>p->data.num;printf("\n添加的姓名:\n");cin>>p->;printf("\n性别:\n");cin>>p->data.sex;printf("\n电话:\n");cin>>p->data.phone;printf("\n地址:\n");cin>>p->data.addr;rear->next=p; //新结点连接到尾结点之后rear=p; //尾指针指向新结点printf("继续建表?(y/n):");cin>>flag;rear->next=NULL; //终端结点指针置空return head; //返回链表头指针}/*********在通讯录链表head中插入结点************/void InsertNode(LinkList head,ListNode *p){ListNode *p1,*p2;p1=head;p2=p1->next;while(p2!=NULL && strcmp(p2->data.num,p->data.num)<0){p1=p2; //p1指向刚访问过的结点p2=p2->next; //p2指向表的下一个结点}p1->next=p; //插入p所指向的结点p->next=p2; //连接表中剩余的结点}/**********有序通讯录链表的查找****************/ListNode *ListFind(LinkList head){ListNode *p;char num[5];char name[9];char pp;printf("==================\n");printf(" a. 按编号查询\n");printf(" b. 按姓名查询\n");printf("==================\n");printf(" 请选择:");p=head->next;cin>>pp;if (pp=='a'||pp=='A'){printf("请输入要查找者的编号:");cin>>num;while (p&&strcmp(p->data.num,num)<0) p=p->next;if ((p==NULL)||strcmp(p->data.num,num)>0) p=NULL; //没有查到要查找的通讯信息}if (pp=='b'||pp=='B'){printf(" 请输入要查找者的姓名:");cin>>name;while(p&&strcmp(p->,name)!=0) p=p->next;}return p;}/********通讯录链表上的结点删除*****************/void DelNode(LinkList head){char cho;ListNode *p,*q;p=ListFind(head); //调用查找函数if (p==NULL){printf("没有查到要删除的通讯者!\n");return;}else if(p!=NULL){printf("真的要删除该结点吗?(y/n)");cin>>cho;if (cho=='y'||cho=='Y'){q=head;while ((q!=NULL)&&(q->next!=p)) q=q->next;q->next=p->next; //删除结点free(p); //释放被删结点空间printf("删除成功!\n");}}}/********通讯录链表的输出函数**********/void PrintList(LinkList head){ListNode *p;p=head->next;printf("编号姓名性别联系电话地址\n");printf("--------------------------------------------------------------------------------\n");while (p!=NULL){printf("%s,%s,%s,%s,%s\n",p->data.num,p->,p->data.sex,p->data.phone,p->data.a ddr);printf("---------------------------------------------------------------------------------\n");p=p->next; //后移一个结点}}void main(){int choice,j=1;while(j){printf("\n\n\n\n\n");printf("\t\t\t\t通信录链表\n");printf("\n\t\t\t******************************");printf("\n\t\t\t* 1--- 通信录链表建立*");printf("\n\t\t\t* 2--- 通信录链表插入*");printf("\n\t\t\t* 3--- 通信录链表查询*");printf("\n\t\t\t* 4--- 通信录链表删除*");printf("\n\t\t\t* 5--- 通信录链表输出*");printf("\n\t\t\t* 0--- 退出管理系统*");printf("\n\t\t\t******************************");printf("\n\t\t\t请选择菜单号(0--5):");cin>>choice;getchar();switch(choice){case 1:{printf("**********************************\n");printf("* 通讯录链表的建立*\n");printf("**********************************\n");head=CreateList( );flag1=1;system("cls");break;}case 2:{if(flag1!=1) {printf("请先建立表!");Sleep(1500); system("cls");}printf("**********************************\n");printf("* 通讯者信息的添加*\n");printf("**********************************\n");printf("编号(4) 姓名(8) 性别(3) 电话(11) 地址(31)\n");printf("************************************* \n");p=(ListNode *)malloc(sizeof(ListNode)); //申请新结点printf("\n添加的编号:\n");cin>>p->data.num;printf("\n添加的姓名:\n");cin>>p->;printf("\n性别:\n");cin>>p->data.sex;printf("\n电话:\n");cin>>p->data.phone;printf("\n地址:\n");cin>>p->data.addr;InsertNode(head,p);system("cls");break;}case 3:{if(flag1!=1) {printf("请先建立表!");Sleep(1500);system("cls");}else{printf("***********************************\n");printf("* 通讯录信息的查询*\n");printf("***********************************\n");p=ListFind(head);if (p!=NULL){printf("编号姓名性别联系电话地址\n");printf("--------------------------------------------------\n");printf("%s,%s,%s,%s,%s\n",p->data.num,p->,p->data.sex,p->data.phone,p->data.a ddr);printf("---------------------------------------------------\n");}else printf("没有查到要查询的通讯者!\n");}break;}case 4:{if(flag1!=1) {printf("请先建立表!"); Sleep(1500);}else{printf("***********************************\n");printf("* 通讯录信息的删除*\n");printf("***********************************\n");DelNode(head); //删除结点}break;}case 5:{if(flag1!=1) {printf("请先建立表!"); Sleep(1500);}else{printf("************************************\n");printf("* 通讯录链表的输出*\n");printf("************************************\n");PrintList(head);}break;}case 0:j=0;system("cls");break;default:printf("\t\t\n 输入有错,请重新输入!\n");Sleep(1500);system("cls");break;}}}。
链表做的通讯录(有要求和源代码宁波工程学院)

三、实验内容1、通讯录设计设计一个班级同学的通讯录,要求如下:✓通讯录中每个同学的信息包含以下内容:学号(id)、姓名(name)、电话号码(tel)。
如果需要更多其他信息,请自行添加。
✓程序主菜单包含以下几个功能:(1)添加记录:通过键盘输入信息,添加一条通讯录记录。
(2)删除记录:通过键盘输入学号,删除该学号的记录。
(3)输出记录:输出通讯录全部记录。
(4)按姓名查找:通过键盘输入姓名,输出该同学的所有信息。
(5)保存记录:把通讯录中所有的记录保存到文件中。
(6)清空记录:删除通讯录中的全部记录,并删除文件。
(7)退出提示:✓程序启动时应判断是否存在记录文件,如果存在,则读取每条记录到链表中。
✓用户选择并完成主菜单某功能后,除了退出程序,应该返回主菜单。
✓添加一条记录时,插入到链表的尾部。
✓查找、删除记录时,如果该记录不存在,则应该输出不存在的提示。
✓添加记录、删除记录时不需要写文件。
✓保存记录时,用覆盖写文件的方法。
(或者先删除原文件,再保存全部记录信息)✓各个功能模块写成函数,由主函数调用。
选做:✓主菜单增加一个排序功能选项,可以按照学号从小到大进行排序。
排序方法可以用冒泡排序或者插入排序。
#include<stdio.h>#include<malloc.h>#include<string.h>#include<stdlib.h>#include<string.h>FILE *fp; //文件指针typedef struct lnode{int id;char name[10];int tel;struct lnode *next;}stud;void Inside(stud *&s,int ID,char *NAME,int TEL); bool Delete(stud *&s,int ID);void Output(stud *s);bool Sereachname(stud *&s,char *NAME); void Memory(stud * s);void Write(stud * s);void Empty(stud *&s);void Ini(stud *&s);void Start(stud *s);int main(){int n,ID,TEL;char NAME[10];stud *s;Ini(s);Start(s);printf("*****************************1.添加记录\t2.删除记录*****************************\n");printf("*****************************3.输出记录\t4.按姓名查找***************************\n");printf("*****************************5.保存记录\t6.清空记录*****************************\n");printf("*****************************7.退出\t***************************************\n");while(~scanf("%d",&n)){if(n>=1&&n<=6){switch(n){case 1:{printf("输入学号、姓名、电话\n");scanf("%d%s%d",&ID,&NAME,&TEL);Inside(s,ID,NAME,TEL);break;}case 2:{printf("请输入“学号”\n");scanf("%d",&ID);Delete(s,ID);break;}case 3:{Output(s);break;}case 4:{printf("请输入“姓名”\n");scanf("%s",&NAME);Sereachname(s,NAME);break;}case 5:{Memory(s);printf("保存成功\n");break;}case 6:{Empty(s);break;}}}if(n==7){printf("***********谢谢使用************\n");break;}printf("*****************************1.添加记录\t2.删除记录*****************************\n");printf("*****************************3.输出记录\t4.按姓名查找***************************\n");printf("*****************************5.保存记录\t6.清空记录*****************************\n");printf("*****************************7.退出\t***************************************\n");}return 0;}void Ini(stud *&s){s=(stud *)malloc(sizeof(stud));s->next=NULL;}void Inside(stud * &s,int ID,char *NAME,int TEL) //输入记录{stud *r,*t=s;while(t->next!=NULL){t=t->next;}r=(stud *)malloc(sizeof(stud));r->id=ID;strcpy(r->name,NAME);r->tel=TEL;r->next=NULL;t->next=(stud *)malloc(sizeof(stud));t->next=r;}bool Delete(stud * &s,int ID) //删除记录{stud *r=s,*q,*pre=s;r=r->next;while(r!=NULL && r->id!=ID) {pre=pre->next;r=r->next;}if(r==NULL){printf("该记录不存在\n"); return false;}else{q=pre->next;pre->next=q->next;free(q);printf("删除成功\n");return true;}void Output(stud *s) //输出记录{if(s!=NULL)s=s->next;if(s!=NULL){while(s!=NULL){ printf("学号\t姓名\t电话\n");printf("%d\t",s->id);printf("%s\t",s->name);printf("%d\n",s->tel);s=s->next;}}else{printf("该通讯录为空\n");}bool Sereachname(stud *&s,char *NAME) //按名字查找{stud *p,*pre=s;p=s->next;while(p!=NULL&&(strcmp(p->name,NAME))){pre=pre->next;p=p->next;}if(p==NULL){printf("该学生不存在\n");return false;}else{printf("学号\t姓名\t电话\n");printf("%d\t",p->id);printf("%s\t",p->name);printf("%d\n",p->tel);return true;}}void Memory(stud * s) //{fp=fopen("d:\\in.txt","w"); //数据保存到文件中if(s!=NULL)s=s->next;while(s!=NULL){fprintf(fp,"%d\t%s\t%d\n",s->id,s->name,s->tel);//写入文件s=s->next;}fclose(fp);}void Empty(stud * &s) //清空记录{stud *p=s,*q=s;p=p->next;if(p!=NULL)q=p->next;while(q!=NULL){free(p);p=q;q=p->next;}free(p);s->next=NULL;printf("该通讯录已空\n");}void Start(stud *s) // 初始化和载入文件中数据{system("color 09"); //屏幕、字体颜色char NAME[10];int ID,TEL;fp=fopen("d:\\in.txt","a"); //从文件中加载数据,如果没有该文件则新建fclose(fp);fp=fopen("d:\\in.txt","r");while(fscanf(fp,"%d%s%d",&ID,NAME,&TEL)!=EOF) //从文件中读入数据Inside(s,ID,NAME,TEL);fclose(fp);}宁波工程学院计科12-1。
双向链表

第8讲 双向链表● 循环单链表的出现,虽然能够实现从任一结点出发沿着链能找到其前趋结点,但时间耗费是O (n) 。
● 如果希望从表中快速确定某一个结点的前趋,另一个解决方法就是在单链表的每个结点里再增加一个指向其前趋的指针域prior 。
这样形成的链表中就有两条方向不同的链,我们称之为双向链表。
● 双向链表的结构定义如下:typedef struct DNode{ ElemType data ;struct DNode *prior ,*next ;}DNode, * DoubleList ;● 双向链表的结点结构如图所示。
图:双链表的结点结构注:● 双向链表也是由头指针唯一确定的,● 增加头结点能使双链表的某些运算变得方便● 由于在双向链表中既有前向链又有后向链,寻找任一个结点的直接前驱结点与直接后继结点变得非常方便。
● 设指针p 指向双链表中某一结点,则有下式成立:p->prior->next = p = p->next->prior●在双向链表中,那些只涉及后继指针的算法,如求表长度、取元素、元素定位等,与单链表中相应的算法相同,● 但对于前插和删除操作则涉及到前驱和后继两个方向的指针变化,因此与单链表中的算法不同。
1、 双向链表的前插操作【算法思想】欲在双向链表第i 个结点之前插入一个的新的结点,则指针的变化情况如图所示:… p …s->prior=p->prior; ①p->prior->next=s;②s->next=p; ③p->prior=s;④【算法描述】int DlinkIns(DoubleList L,int i,ElemType e){DNode *s,*p;… /*先检查待插入的位置i是否合法(实现方法同单链表的前插操作)*/… /*若位置i合法,则找到第i个结点并让指针p指向它*/s=(DNode*)malloc(sizeof(DNode));if (s){ s->data=e;s->prior=p->prior; ①p->prior->next=s; ②s->next=p; ③p->prior=s; ④r eturn TRUE;}else return FALSE;}2、双向链表的删除操作【算法思想】欲删除双向链表中的第i个结点,则指针的变化情况如图所示:p->prior->next=p->next; ①p->next->prior=p->prior; ②free(p);【算法描述】int DlinkDel(DoubleList L,int i,ElemType *e){DNode *p;… /*先检查待插入的位置i 是否合法(实现方法同单链表的删除操作)*/… /*若位置i 合法,则找到第i 个结点并让指针p 指向它*/*e=p->data;p->prior->next=p->next; ①p->next->prior=p->prior; ②free(p);return TRUE;}3、 双向循环链表双向链表可以有循环表,称为双向循环链表。
双向链表的应用实例

双向链表的应⽤实例管理单向链表的缺点分析:1. 单向链表,查找的⽅向只能是⼀个⽅向,⽽双向链表可以向前或者向后查找。
2. 单向链表不能⾃我删除,需要靠辅助节点,⽽双向链表,则可以⾃我删除,所以前⾯我们单链表删除节点时,总是找到 temp,temp 是待删除节点的前⼀个节点。
双向链表如何完成遍历,添加,修改和删除的思路 1) 遍历:和单链表⼀样,只是可以向前,也可以向后查找 2) 添加 (默认添加到双向链表的最后) (1)先找到双向链表的最后这个节点 (2) temp.next = newNode; (3) newNode.pre = temp; 3) 修改思路和原来的单向链表⼀样 4) 删除 (1) 因为是双向链表,因此,我们可以实现⾃我删除某个节点 (2) 直接找到要删除的这个节点,⽐如 temp temp.pre.next = temp.next; temp.next.pre = temp.pre;//若删除的是最后⼀个节点,会有空指针异常代码实现1. class doublelinkedlist {2. //先初始化⼀个头节点,头节点不能动,不存放具体数据3. private hero head = new hero(-1, "", "");4.5. //添加节点6. public void add(hero h) {7. //因为head节点不能动,因此我们需要⼀个辅助变量temp8. hero temp = head;9. //遍历链表,找到最后⼀个节点10. while (true) {11. if (temp.getNext() == null) {12. break;13. }14. //如果没有到最后,将temp后移15. temp = temp.getNext();16. }17. //当退出while循环时,temp就指向了链表的最后18. //将链表的最后⼀个节点的next指向要添加的这个节点19. //将要添加的这个节点的pre指向链表的最后⼀个节点20. temp.setNext(h);21. h.setPre(temp);22. }23.24. //第⼆种⽅式在添加英雄时,根据排名将英雄插⼊到指定位置25. //(如果有这个排名,则添加失败,并给出提⽰)26. public void addByOrder(hero h) {27. //因为头节点不能动,因此我们仍然通过⼀个辅助指针(变量)来帮助找到添加的位置28. hero temp = head;29. boolean flag = false;// flag 标志添加的编号是否存在,默认为 false30. while (true) {31. if (temp.getNext() == null) {//说明 temp 已经在链表的最后32. break;33. } else if (temp.getNext().getNum() > h.getNum()) {//位置找到,就在 temp 的后⾯插⼊34. break;35. } else if (temp.getNext().getNum() == h.getNum()) {//说明希望添加的 heroNode 的编号已然存在36. flag = true;37. break;38. }39. temp = temp.getNext();//后移,遍历当前链表40. }41. if (flag) { //不能添加,说明编号存在42. System.out.println("添加的序号为" + h.getNum() + "的英雄序号已经存在,添加失败。
LinkList(双向链表实现)

LinkList(双向链表实现)LinkedList是⽤链表结构存储数据的,⽐较适合数据的动态插⼊和删除,随机访问和遍历速度⽐较慢,还提供了List接⼝i中没有定义的⽅法,专门⽤于操作表头和表尾的元素,所以可以当作堆栈、队列和双向队列来使⽤。
LInkedList持有头节点和尾节点的引⽤,有两个构造器,⼀个是⽆参构造器,另⼀个是传⼊外部集合构造器,它没有像ArrayList⼀样的初始⼤⼩的构造器。
1//集合元素个数23transient int size = 0;4567//头结点引⽤89transient Node<E> first;10111213//尾节点引⽤14transient Node<E> last;1516//⽆参构造器17public LinkedList() {}1819//传⼊外部集合的构造器20public LinkedList(Collection<? extends E> c) {21this();22 addAll(c);23 }2425//增(添加)26public boolean add(E e) {2728//在链表尾部添加29 linkLast(e);30return true;31 }323334//增(插⼊)35public void add(int index, E element) {3637 checkPositionIndex(index);3839if (index == size) {40//在链表尾部添加41 linkLast(element);42 } else {43//在链表中部插⼊44 linkBefore(element, node(index));45 }46 }47484950//删(给定下标)51public E remove(int index) {5253//检查下标是否合法54 checkElementIndex(index);55return unlink(node(index));56 }5758//删(给定元素)59public boolean remove(Object o) {60if (o == null) {61for (Node<E> x = first; x != null; x = x.next) {62if (x.item == null) {63 unlink(x);64return true;65 }66 }67 } else {68//遍历链表69for (Node<E> x = first; x != null; x = x.next) {70if (o.equals(x.item)) {71//找到了就删除72 unlink(x);73return true;74 }75 }76 }77return false;78 }79808182//改83public E set(int index, E element) {8485//检查下标是否合法86 checkElementIndex(index);8788//获取指定下标的结点引⽤89 Node<E> x = node(index);9091//获取指定下标结点的值9293 E oldVal = x.item;9495//将结点元素设置为新的值9697 x.item = element;9899//返回之前的值100101return oldVal;102103 }104105106//查107public E get(int index) {108109//检查下标是否合法110 checkElementIndex(index);111112//返回指定下标的结点的值113return node(index).item;114 }LinkedList的添加元素的⽅法主要是调⽤LinkLast和LinkBefore两个⽅法,LinkLast⽅法是在链表后⾯链接⼀个元素,LinkBefore⽅法是在链表中间插⼊⼀个元素。
通讯录 双向链表

//node.h#include<iostream.h>#include<fstream.h>#include<string.h>#include<stdlib.h>#include<iomanip.h>struct data //数据{char name[20]; //姓名char tel[20]; //电话int age; //年龄};class node //节点{friend class link; //友远类private:data person; //数据node * next;node * pre;public:void show() //显示数据信息{cout<<"姓名:"<<setw(20)<<<<endl;cout<<"电话:"<<setw(20)<<person.tel<<endl;cout<<"年龄:"<<setw(3)<<person.age<<endl<<endl;}node(char*name0="",char*tel0="",int age0=0) //构造函数{strcpy(,name0);strcpy(person.tel,tel0);person.age=age0;next=NULL;pre=NULL;}node(node&n) ////拷贝构造{strcpy(,);strcpy(person.tel,n.person.tel);person.age=n.person.age;}};class link{ //双向链表node * head; //头指针node * rear; //尾指针node * findbyname(char*name0,node *temp ) //查找姓名返回地址{temp=head;if(!head) //空链表{cout<<"通讯录中没有信息"<<endl<<endl;return NULL;}node * p=head;while(p){if(strcmp(p->,name0)==0) //已找到return p;p=p->next;}while(temp){if(Cmpstr(temp->,name0)){cout<<endl<<"符合条件的记录,如下:"<<endl;temp->show();}temp=temp->next;}//if(temp)// cout<<"查无此人"<<endl<<endl;//未找到}return temp;}node * findbyname(char*name0) //查找姓名返回地址{if(!head) //空链表{cout<<"通讯录中没有信息"<<endl<<endl;return NULL;}node * p=head;while(p){if(strcmp(p->,name0)==0) //已找到return p;p=p->next;}if(!p)cout<<"查无此人"<<endl<<endl;return NULL;//未找到}int length() //返回链表长度{if(!head)return 0;node*p;int n=1;p=head;if(p->next){p=p->next;n++;}return n;}node * findbynum(int num) //根据序号查找{int l=length(); //l为总长if(!head) //空链表{cout<<"通讯录中没有信息"<<endl<<endl;return NULL;}if(num>l) //数据越界{cout<<"通讯录里没有"<<num<<"条信息"<<endl<<endl;return NULL;}node * p=head;while(--num)p=p->next;return p; //返回指针}void change(node*p)//修改对应指针信息{char tel0[20];int age0,cho;cout<<"请输入新的电话号码"<<endl;cin>>tel0;cout<<"请输入新的年龄"<<endl;cin>>age0;cout<<"姓名:"<<p-><<endl;cout<<"原电话号码:"<<setw(20)<<p->person.tel<<endl;cout<<"原年龄:"<<setw(3)<<p->person.age<<endl<<endl;cout<<"新电话号码:"<<setw(20)<<tel0<<endl;cout<<"新年龄:"<<setw(3)<<age0<<endl<<endl;cout<<"1.确认 2.取消"<<endl;cin>>cho;if(cho==1){strcpy(p->person.tel,tel0);p->person.age=age0;cout<<"已修改成功"<<endl;}}void del(node *p) //删除一个节点{if(!head) //空链表{cout<<"通讯录中没有信息"<<endl<<endl;return ;}if(p==head) //删除头结点{p->next->pre=NULL;head=p->next;delete p;return;}if(p==rear) //删除尾节点{p->pre->next=NULL;rear=p->pre;delete p;return;}p->next->pre=p->pre; //删除中间节点p->pre->next=p->next;delete p;}void delall() //删除整个链表{node*p;while(head){p=head;head=head->next;delete p;}head=rear=NULL;}public:link() //构造函数{head=rear=NULL;}~link(){ //析构函数,同时释放链表空间delall();}node * cinnode() //从键盘输入生成一个节点{char name[20],tel[20];int age;node*p;p=new node;cout<<"请输入姓名"<<endl;cin>>name;cout<<"请输入电话号码"<<endl;cin>>tel;cout<<"请输入年龄"<<endl;cin>>age;*p=node(name,tel,age);return p;}void insert(node *p) //将节点插入链表{node *p1,*p2;if(head==0) //空链表{p->next=0;p->pre=0;head=rear=p;return;}if(strcmp(head->,p->)>0){p->next=head;head->pre=p;p->pre=0;head=p;return;}if(strcmp(rear->,p->)<0){p->pre=rear;rear->next=p;p->next=0;rear=p;return ;}p1=p2=head;while(strcmp(p2->,p->)<0){p1=p2;p2=p2->next;}p->next=p2; //插入链表中间p2->pre=p;p1->next=p;p->pre=p1;}void showfromhead() //从前向后输出链表{if(!head) //空链表cout<<"通讯录无信息"<<endl;else{int c=0;node *p;p=head;while(p){p->show(); //调用函数显示信息p=p->next;c++;//if(c%5==0) //控制每输出 5 个暂停一次//system("pause");}cout<<"所有信息输出完成"<<endl;}}void showfromrear() //从后向前输出链表{if(!rear)cout<<"通讯录无信息"<<endl;else{int c=0;node*p;p=rear;while(p){p->show();p=p->pre;c++;if(c%6==0)system("pause");}cout<<"所有信息输出完成"<<endl;}}void showbyname(node *temp) //根据姓名显示信息{char name[20];cout<<"请输入欲查找的姓名"<<endl;cin>>name;node *p;p=findbyname(name,temp); //查找姓名所对应的指针if(p)p->show();}void changebyname() //根据姓名修改信息{char name[20];cout<<"请输入欲修改的姓名"<<endl;cin>>name;node*p;p=findbyname(name);if(p)change(p);}void delbyname() //根据姓名删除信息{char name[20];if(!head) //空链表{cout<<"通讯录中没有信息"<<endl<<endl;return ;cout<<"请输入欲删除的姓名"<<endl;cin>>name;node*p;p=findbyname(name);if(p)del(p);cout<<"已删除选定信息"<<endl;}void showbynum() //根据序号显示信息{int num;if(!head) //空链表{cout<<"通讯录中没有信息"<<endl<<endl;return ;}cout<<"请输入欲查找编号"<<endl;cin>>num;node*p;p=findbynum(num); //根据序号查找指针if(p)p->show();}void delbynum() //根据序号删除信息{int num;if(!head) //空链表{cout<<"通讯录中没有信息"<<endl<<endl;return ;}cout<<"请输入欲删除编号"<<endl;cin>>num;node*p;p=findbynum(num);if(p)del(p);cout<<"已删除选定信息"<<endl;}void changebynum() //根据序号修改信息{int num;if(!head) //空链表cout<<"通讯录中没有信息"<<endl<<endl;return;}cout<<"请输入欲修改编号"<<endl;cin>>num;node*p;p=findbynum(num);if(p)change(p);}void inputnode()//从文件读入{char filename[30];cout<<"输入数据源文件名"<<endl;cin>>filename;ifstream fin(filename,ios::in|ios::nocreate);if(!fin){cout<<"无法打开指定文件"<<endl;exit(1);}char name[20],tel[20];int age;node *p;while(fin>>name){fin>>tel>>age;p=new node(name,tel,age);insert(p);}fin.close();}void outfromhead() //顺序输出至文件{char filename[30];cout<<"输入数据目标文件名"<<endl;cin>>filename;ofstream fout(filename);if(!fout){cout<<"无法打开指定文件"<<endl;exit(1);}if(!head)fout<<"通讯录无信息"<<endl;else{node*p;p=head;while(p){fout<<"姓名:"<<setw(20)<<p-><<endl;fout<<"电话:"<<setw(20)<<p->person.tel<<endl;fout<<"年龄:"<<setw(3)<<p->person.age<<endl<<endl;;p=p->next;}cout<<"所有信息输出完成"<<endl;}}void outfromrear() //逆序输出至文件{char filename[30];cout<<"输入数据目标文件名"<<endl;cin>>filename;ofstream fout(filename);if(!fout){cout<<"无法打开指定文件"<<endl;exit(1);}if(!rear)fout<<"通讯录无信息"<<endl;else{node*p;p=rear;while(p){fout<<"姓名:"<<setw(20)<<p-><<endl;fout<<"电话:"<<setw(20)<<p->person.tel<<endl;fout<<"年龄:"<<setw(3)<<p->person.age<<endl<<endl;;p=p->pre;}cout<<"所有信息输出完成"<<endl;}}bool Cmpstr(char*name_node,char*name_search)//传统型字符串比较函数,支持通配符*,?及大小写转换,name_node等于name_search时,返回true{if(name_search[0]=='*') //通配符*,通配任意字符串,返回truereturn true;char name1[20],name2[20];//避免改变原结点中的信息strncpy(name1,name_node,20);strncpy(name2,name_search,20);int size1=strlen(name1),size2=strlen(name_search);for(int i=0;i<size2;i++){if(name2[i]>='A'&&name2[i]<='Z')//大写全部转换为小写,以便于比较,人性化处理name2[i]+=32;}for(int i1=0;i1<size1;i1++){if(name1[i1]>='A'&&name1[i1]<='Z')//大写全部转换为小写,以便于比较,人性化处理name1[i1]+=32;}for(int i2=0;i2<size1;i2++){if(name_search[i2]=='*')//通配符*,通配任意字符串,{for(int j=0;j<i2;j++){if(name1[j]!=name2[j])return false;}return true;}}if(size1!=size2)//不等长时,即两字符串不相等,返回false{return false;}for(int i3=0;i3<size1;i3++){if(name2[i3]=='?')//通配符‘?’,通配任一字符continue;if(name1[i3]!=name2[i3])return false;}return true;}};//main.cpp#include "node.h"void main();char buffer[100];void show_data(link &a){char c;cout<<"查看全部数据"<<endl;cout<<"1.顺序 2.逆序"<<endl;cin>>c;if(c=='1'){a.showfromhead();system("pause");cout<<endl<<endl;system("cls");return;}if(c=='2'){a.showfromrear();system("pause");cout<<endl<<endl;system("cls");return;}if(c!='1'&&c!='2'){cout<<"input error"<<endl;system("pause");cout<<endl<<endl;system("cls");void show_data(link &a);return;}};void delet_data(link &a){char c;cout<<"删除数据"<<endl;cout<<"1.根据序号删除数据 2.根据姓名删除数据"<<endl;cin>>c;if(c=='1'){a.delbynum();system("pause");cout<<endl<<endl;system("cls");}if(c=='2'){a.delbyname();system("pause");cout<<endl<<endl;system("cls");}if(c!='1'&&c!='2'){cout<<"input error"<<endl;system("pause");cout<<endl<<endl;system("cls");void delet_data(link &a);}};void insert_data(link &a){cout<<"添加数据"<<endl;a.insert(a.cinnode());system("pause");cout<<endl<<endl;system("cls");};void updata(link &a){char c;cout<<"修改数据"<<endl;cout<<"1.根据序号修改数据 2.根据姓名修改数据"<<endl;cin>>c;if(c=='1'){a.changebynum();system("pause");cout<<endl<<endl;system("cls");}if(c=='2'){a.changebyname();system("pause");cout<<endl<<endl;system("cls");}if(c!='1'&&c!='2'){cout<<"input error"<<endl;system("pause");cout<<endl<<endl;system("cls");void updata(link &a);}};void search_data(link &a){char c;node *temp;cout<<"查找数据"<<endl;cout<<"1.根据序号查找数据 2.根据姓名查找数据(支持*与?的通配)"<<endl;cin>>c;if(c=='1'){a.showbynum();system("pause");cout<<endl<<endl;system("cls");}if(c=='2'){a.showbyname(temp);system("pause");cout<<endl<<endl;system("cls");}if(c!='1'&&c!='2'){cout<<"input error"<<endl;system("pause");cout<<endl<<endl;system("cls");void search_data(link &a);}};void output_data(link &a){char c;cout<<"将数据输出至文件"<<endl;cout<<"1.升序 2.降序"<<endl;cin>>c;if(c=='1'){a.outfromhead();system("pause");cout<<endl<<endl;system("cls");}if(c=='2'){a.outfromrear();system("pause");cout<<endl<<endl;system("cls");}if(c!='1'&&c!='2'){cout<<"input error"<<endl;system("pause");cout<<endl<<endl;system("cls");void output_data(link &a);}};link a;void menu(){char c;cout<<"\t\t 通讯录管理系统"<<endl;cout<<"1.查看全部数据"<<endl;cout<<"2.删除数据"<<endl;cout<<"3.添加数据"<<endl;cout<<"4.修改数据"<<endl;cout<<"5.查找数据"<<endl;cout<<"6.从文件输入数据"<<endl;cout<<"7.将数据输出至文件"<<endl;cout<<"8.退出"<<endl<<endl;cout<<"请输入您需要的功能"<<endl;cin>>c;switch(c){case '1':show_data(a);menu();break;case '2':delet_data(a);menu();break;case '3':insert_data(a);menu();break;case '4':updata(a);menu();break;case '5':search_data(a);menu();break;case '6':cout<<"从文件输入数据"<<endl;a.inputnode();system("pause");cout<<endl<<endl;system("cls");menu();break;case '7':output_data(a);menu();break;case '8':cout<<"谢谢使用"<<endl;return ;default:{cin.clear();cin.getline(buffer,100);cout<<"input error "<<endl;system("pause");system("cls");menu();}}return;}void main() //显示菜单,并调用对应函数{menu();}。
通讯录的设计_数据结构课程设计(含代码)

课程设计说明书课程名称:数据结构课程设计专业:电子信息科学与技术班级:2012-1 设计人:山东科技大学2015年7月11日目录1需求分析说明 (1)2概要设计说明 (1)2.1 数据结构定义 (1)2.2 整体程序流程图 (2)3详细设计说明 (3)3.1主函数模块 (3)3.2 增加联系人模块 (3)3.3 删除联系人模快 (3)3.4 查找联系人模块 (4)3.5 联系人保存到文件模块 (5)3.6 读取文件中的联系人信息模块 (6)3.7命令接收与判断模块 (8)3.8显示联系人信息模块 (8)4调试分析 (8)4.1遇到的问题 (8)4.2调试 (8)5用户使用说明 (11)6课程设计总结 (12)1需求分析说明通讯录管理系统总体设计目标:用《数据结构》中的双向链表作数据结构,结合C语言基本知识,编写一个具有良好可操作性、有一定容错能力通讯录管理系统,以把所学数据结构知识应用到实际软件开发中去。
其中联系人的信息包括姓名、街道、城市、邮编、国家等几项。
系统在命令行模式下运行,通过输入命令的方式操作。
根据以上基本要求分析出系统应具备以下功能:显示所有联系人信息,向通讯录中添加新的联系人,删除指定联系人,将联系人信息保存到文件中,从文件中读取联系人信息到内存,以姓名为关键字查找联系人。
根据以上要实现的功能,首先要构造一个保存联系人信息的数据结构person_info,根据要求这个结构应具有两个指针域以指向其前一个结构和后一个结构从而构成双链表;其数据域包括姓名、街道、城市、邮编、国家等信息,这些信息分别保存在字符数组中。
除了基本的联系人结构(相当于双链表的一个结点)还应构造一个person_list结构,包括一个指向第一个联系人结点的指针和一个保存链表长度的元素。
2概要设计说明2.1数据结构定义考虑到本系统在初始化阶段要进行大规模的插入操作以构造链表,故采用插入元素较为方便快速的链式存储结构。
链表实现c语言通讯录管理系统,C++链表实现通讯录管理系统

链表实现c语⾔通讯录管理系统,C++链表实现通讯录管理系统⽤数据结构⾥⾯线性结构的链表实现,供⼤家参考,具体内容如下⽂件操作未写有登录操作,复制源码需要更改登录模块的密码⽂件存放位置使⽤VS2017编译器需要保留开头:#define _CRT_SECURE_NO_WARNINGS#define _CRT_SECURE_NO_WARNINGS#include "iostream"#include "cstdio"#include "fstream"#include "stdlib.h"#include "String"#include "iomanip"#include "windows.h"#define LEN 100using namespace std;using std::cin;using std::cout;using std::endl;using std::ifstream;using std::ofstream;using std::ios;using std::cerr;using std::string;using std::setw;typedef struct LNode {char num[10];char name[20];char telNum[12];char qq[10];struct LNode *next;}LNode,*LinkList;int n = 0;LinkList SearchName(LinkList L);//按姓名查找LinkList SearchNum(LinkList L);//按学号查找void DelLNode(LinkList &L,LinkList p);//删除p结点void PrintLNode(LinkList p);//打印结点void PrintList(LinkList L);//打印表/*----------------系统函数----------------*/void CreateLinkList(LinkList &L);//创建链表void DelName(LinkList &L);//按姓名删除通讯录成员void DelNum(LinkList &L);//按学号删除通讯录成员void saveRecord(LinkList L);//存储信息void loadRecord(LinkList &L);//加载信息/*--------------------------------------*/void Secret();void fun();void ver();void yanshi(char *p);void clear();void header();void menu() {LinkList L=NULL;int select;do {system("cls");printf("\t\t\t Welcome to the address book information management system!\n\n\n"); printf("\t\t\t\t***************************************************\n");printf("\t\t\t\t * │1.InitList 2.Add Message │ *\n");printf("\t\t\t\t * │ │ *\n");printf("\t\t\t\t * │3.Search Message 4.Save File │ *\n");printf("\t\t\t\t * │ │ *\n");printf("\t\t\t\t * │5.Sort Static 6.Load Message │ *\n");printf("\t\t\t\t * │ │ *\n");printf("\t\t\t\t * │7.Display Message 8.Delete Message│ *\n");printf("\t\t\t\t***************************************************\n");cout << endl;yanshi((char *)"\t\tPlease choose the mode of operation(1~8):\n");/* cout << "\t\tPlease choose the mode of operation(1~8):" << endl;*/cin >> select;switch (select) {case 8:cout << "Please select the deletion method:\n1.Delete by student number 2.Delete by name\n" << endl; int x;cin >> x;switch (x) {case 1:DelNum(L);break;case 2:DelName(L);break;}case 6:loadRecord(L);break;case 5:break;case 4:saveRecord(L);break;case 3:clear();cout << "Please select a search method:\n1.Find by student number 2.Find by name\n" << endl;int a;cin >> a;switch (a) {{LinkList aa = SearchNum(L); header();PrintLNode(aa);cout << "\n\n\n成功!" << endl; system("pause");menu();}break;case 2:clear();{LinkList b = SearchName(L); header();PrintLNode(b);cout << "\n\n\n成功!" << endl; system("pause");menu();break;}}break;case 1:InitList(L);break;case 9:break;case 7:PrintList(L);break;case 2:CreateLinkList(L);cout << endl << endl << endl;cout << "The programe is over!" << endl << endl << endl; Sleep(2000);exit(0);break;}} while (select != 8);}int main() {fun();ver();//版本信息Secret();//密码登录menu();return 0;}//初始化表void InitList(LinkList & L){L = new LNode;//申请头结点L->next= NULL;}//插⼊⼀条信息void InsertLNode(LinkList & L, LNode *s){s->next = L->next;L->next = s;}//按姓名查找LinkList SearchName(LinkList L){char name[20];cout << "请输⼊要查找的姓名:" << endl;while (p) {//如果找到,退出循环,返回pif (strcmp(p->name, name) == 0) break;elsep = p->next;}return p;}//按学号查找LinkList SearchNum(LinkList L){char num[10];cout << "请输⼊要查找的学号:" << endl; cin >> num;LinkList p = L->next;while (p) {//如果找到,退出循环,返回pif (strcmp(p->num, num) == 0) break;elsep = p->next;}return p;}//删除节点void DelLNode(LinkList &L,LinkList p) {LinkList s=NULL, q;q = L->next;//将s指向p前⾯的⼀个结点while (q&&q!=p) {}s->next = q->next;delete q;}//打印⼀条信息void PrintLNode(LinkList p){printf("%15s", p->num);printf("%15s", p->name);printf("%15s", p->telNum);printf("%15s\n",p->qq);}//打印通讯录void PrintList(LinkList L){clear();header();LinkList p = L->next;while (p) {PrintLNode(p);p = p->next;}system("pause");}//添加信息void CreateLinkList(LinkList & L) {char ans = 'y';n = 0;while (ans=='y'||ans=='Y') { system("cls");LNode *p = new LNode;cout << "请输⼊姓名:" << endl;cin >> p->name;cout << "请输⼊电话号码:" << endl;cin >> p->telNum;cout << "请输⼊QQ号:" << endl;cin >> p->qq;InsertLNode(L,p);n++;cout<getchar();ans=getchar();}system("pause");}//按姓名删除void DelName(LinkList &L){char name[20];LinkList p;cout << "请输⼊要删除的学⽣姓名:" << endl; cin >> name;p = SearchName(L);if (p) {DelLNode(L,p);}system("pause");}//按学号删除void DelNum(LinkList & L){char num[20];LinkList p;p = SearchName(L);if (p) {DelLNode(L, p);}system("pause");}//存储信息void saveRecord(LinkList L){FILE *fp=NULL;int count = 0;if ((fp=(fopen("student.dat","wb")))==NULL) { cout << "Can't open this file!" << endl;Sleep(3000);}LinkList q = L->next;while (q) {fwrite(q, sizeof(LNode), 1, fp);count ++;q = q->next;}fclose(fp);cout << "Save the file successfully!" << endl; getchar();}//加载信息void loadRecord(LinkList & L){FILE *fp=NULL;int count = 0;if ((fp=(fopen("student.dat", "rb"))) == NULL) { cout << "Can't open this file!" << endl;LinkList p=NULL;while(1){p = new LNode;if (fread(p, sizeof(LNode), 1, fp) > 0) {InsertLNode(L,p);count++;}else {break;}}fclose(fp);cout << endl << endl << "Load "<Sleep(2200);}//控制台样式void fun() {system("color 2a");system("title 学⽣通讯录信息管理系统");}//版本信息void ver(){yanshi((char*)"\t \3\3\3\3\3\3\3欢迎使⽤通讯录信息管理系统\3\3\3\3\3\3\3\n\n\n\n"); cout << "\t 学⽣通讯录信息管理系统\n\n\n\n\n";cout << "\t\t version 1.0\n\n\n\n\n";cout << "\t\t xxxxxxxxx 某某某\n\n\n\n\n";cout << "\t\t Loading......\n\n" << endl;Sleep(3000);system("cls");}//延时输出while (1) {if (*p != 0)cout << *p++;elsebreak;Sleep(50);}}//清屏void clear(){system("cls");}//表头void header(){printf("%15s%15s%15s%15s\n","学号","姓名","电话","QQ");}/*--------------------------------登录模块----------------------------------*//*--------------------------------登录模块----------------------------------*//*--------------------------------登录模块----------------------------------*/struct UsrInfo//⽤户名的账户和密码信息{char UsrName[20];char Psword[20];};/*注意我的⽂件中⽤户名是⼀⾏,密码是⼀样。
数据结构-链表(二)-通讯录-C++实现

数据结构-链表(⼆)-通讯录-C++实现通讯录的元素是⼈,所以需要新建⼀个Person类作为链表每个Node的元素。
并且为了正常输出,Person还需要⾍重载⼀些运算符,包括输出<<,判等==main函数⾥也要写⼀些辅助函数来获取信息。
链表本⾝实现部分不需要修改太多,把原来的的int型元素改为Person类型即可代码如下//Person.h#pragma once#include<iostream>#include<string>using namespace std;class Person{friend ostream& operator<<(ostream& out,Person &p){out << "Name: "<<<<"---" <<"Pnone number: "<< p.phone << endl;return out;}public:Person(string na, int num);Person();~Person();bool operator ==(Person &p){if ((this->name == ) && (this->phone == p.phone)){return true;}else{return false;}}string name="张三";int phone=0;private:};//Person.cpp#include"Person.h"Person::Person(string na, int num):name(na),phone(num){}Person::Person(){}Person::~Person(){}//Node.h#pragma onceusing namespace std;#include<iostream>#include"Person.h"class Node{public:Node(Person a);Node();~Node();Person person;Node* next;private:};//Node.cpp#include"Node.h"Node::Node(Person a):person(a){}Node::Node(){}Node::~Node(){}//List.h#pragma once#include<iostream>using namespace std;#include"Node.h"#define __debug__#ifdef __debug__#endifclass List{public:List();//~List();//bool get_add_head(Node* e);//在头节点后⾯插⼊bool get_add_tail(Node* e);//在尾节点后⾯插⼊void get_traverse();//遍历int get_length();//获取长度bool get_empty();//判空void get_clear();//清空线性表int get_ele_num(Node* p);//获取与传⼊参数值相同的链表中元素的序号 bool get_i_ele(int e, Node* value);//获指定位序的元素void get_delete(int location);//删除某位置元素bool get_add(int location, Node* e);//添加在某位置元素bool get_pre(Node* e, Node* pre);//获取前驱bool get_post(Node* e, Node* pos);//获取后继private:Node* node;//头节点int length;};//List.cpp#include"List.h"List::List(){length = 0;node = new Node;node->="zhangsan";node->person.phone = 0;node->next = NULL;}List::~List(){get_clear();delete node;node = NULL;}bool List::get_add_head(Node* e){Node* c_node = new Node;c_node=node->next;Node* new_node = new Node;if (new_node == NULL){return false;}new_node->person = e->person;new_node->next = c_node;node->next = new_node;length++;#ifdef __debug__cout << node->next->person << endl;#endifreturn true;}bool List::get_add_tail(Node* e){Node* c_node = new Node;c_node = node;while (c_node->next!=NULL){c_node = c_node->next;}Node* new_node = new Node;if (new_node == NULL){return false;}new_node->person = e->person;new_node->next = NULL;c_node->next = new_node;length++;#ifdef __debug__cout << c_node->next->person << endl;#endifreturn true;}void List::get_traverse(){Node* c_node = new Node;c_node = node->next;while (c_node != NULL){cout << c_node->person << endl;c_node = c_node->next;}}//遍历int List::get_length(){return length;}//获取长度bool List::get_empty(){return length == 0 ? true : false;}void List::get_clear(){Node* c_node = new Node;c_node = node;while(c_node->next != NULL){Node* new_node = new Node;new_node=c_node->next;delete c_node;//清除指向的内容c_node = new_node;}length = 0;node->next = NULL;//易错,勿忘!}//清空线性表int List::get_ele_num(Node* p)//获取元素的位序{Node* c_node = new Node;c_node=node;int count = 1;while (c_node->next != NULL){c_node = c_node->next;if (c_node->person == p->person){return count;}else{count++;}}return -1;}bool List::get_i_ele(int e, Node* value){if (e <1 || e > length){cout << "Invalid num!" << endl;return false;}Node* c_node = new Node;c_node = node;for (int i = 0; i <e; i++){c_node = c_node->next;}value->person = c_node->person;#ifdef __debug__cout << c_node->person << endl;#endifreturn true;}//获指定位序元素的值//void List::get_delete(int location){if (location<1 || location>length ){cout << "invalid num!!" << endl;}else{Node* c_node = new Node;c_node = node;Node* c_node_before = new Node;for (int i = 0; i < location; i++)//遍历到了location对应的位置,与增加元素有所不同,需要注意! {c_node_before = c_node;c_node = c_node->next;}c_node_before->next = c_node->next;length--;}}//某位置删除元素//bool List::get_add(int location, Node* e){if (location<1 || location>length){cout << "Invalid num!" << endl;return false;}else{Node* c_node = new Node;c_node=node;for (int i = 0; i < (location-1); i++){c_node = c_node->next;}//此时是遍历到了(location-1)那个元素的位置,然后在其后⾯插⼊新元素则是第location个元素。
C++实现的电话薄管理(双向链表)

/*************************************************************************《C++程序设计实践指导》* 第2章 2.2 用双向链表实现电话薄管理* (c) yrmuhon, 2009 2.10************************************************************************/#include <fstream>#include <iostream>#include <iomanip>#include <string>#include <cstdlib>using namespace std;/*----------------------------------------------------------------------------- |【部分1】|命名空间下的结构体类 friend_node 结点和用于封装函数的 record 类的定义部分-----------------------------------------------------------------------------*/ namespace NameRecord // 定义命名空间 NameRecord{// 结构体类 friend_node 结点(结点即:一组存放姓名、名子和电话号码的数据结构,插入 1个结点则表示建立一个结点对象,即:增加一个姓名电话记录)struct friend_node{char user_name[20]; // 存放姓名char phone_num[12]; // 存放电话号码friend_node * next; // 定义 next 为指向下一个结点的指针,又称后向指针friend_node * prior; // 定义 prior 为指向前(上)一个结点的指针,又称前向指针};friend_node * head_ptr; // 头指针:指向链表头结点的指针friend_node * tail_ptr; // 尾指针:指向链表尾结点的指针friend_node * current_ptr; // 当前指针:指向链表中某个正在处理的结点位置的指针char pause; // 全局变量// 用于封装函数的 record 类class record{public:void UserChoice(int choice); // 根据用户输入的选择调用不同的函数void InsertRecord(); // 插入记录void InsertNode(friend_node * new_ptr); // 插头结点void InsertNodeAtHead(friend_node * new_ptr); // 插入新的头结点void InsertNodeAtEnd(friend_node * new_ptr); // 插入新的尾结点void ShowList(); // 分屏显示记录void DeleteRecord(); // 删除记录void DeleteNodeAtHead(); // 删除头结点void DeleteNodeAtEnd(); // 删除尾结点void DeleteNodeAtMiddle(); // 删除中间结点int VerifyDelete(); // 确认删除void DeleteNode(); // 删除结点void DeleteList(); // 删除链表,释放空间void SearchByLastName(); // 根据姓名搜索电话号码记录void SaveFile(); // 将链表写回文件void LoadFile(); // 将文件中的内容存入链表中void Help(); // 帮助信息void ModifyRecord(); // 修改记录void UserInput(); // 接收用户选择};}/*------------------------------------------------------------------|【部分2】|主函数部分-----------------------------------------------------------------*/using namespace NameRecord; // 使用标准命名空间 NameRecord// 主函数int main(){record myrecord; // 定义 record类的对象 myrecordcout << "欢迎使用 PhoneBook 电话薄管理 1.0\n";cout << "按Enter键继续\n";cin.get(pause);system("cls"); // 清屏int choice;head_ptr = NULL; // 头指针赋值 0,即让头指针不指向任何结点tail_ptr = NULL; // 尾指针赋值 0,即让尾指针不指向任何结点myrecord.LoadFile(); // 调用 LoadFile() 成员函数,从文件中读取数据do{cout << "1:新增记录\n";cout << "2:显示所有记录\n";cout << "3:按姓名搜索记录\n";cout << "4:删除记录\n";cout << "5:修改记录\n";cout << "6:帮助信息\n";cout << "7:退出程序\n";cout << "输入你的选择:";cin >> choice; // 接收用户选择erChoice(choice); // 调用 UserChoice() 成员函数,来处理选择}while( choice!=7 );system("pause");return 0;}/*----------------------------------------------------------------------------- |【部分3】| 所有函数的定义部分|| void record::UserChoice(int choice) // 根据用户输入的选择调用不同的函数| void record::InsertRecord() // 插入记录| void record::InsertNode(friend_node * new_ptr) // 将结点插入到双向链表中| void record::InsertNodeAtHead(friend_node * new_ptr) // 将新结点作为头结点插入到链表中| void record::InsertNodeAtEnd(friend_node * new_ptr) // 将新结点插入到链表中,成为尾结点| void record::ShowList() // 显示链表结点中的数据| void record::SearchByLastName() // 根据姓名搜索链表中符合条件的结点| void record::DeleteRecord() // 删除链表中符合条件的结点| void record::Help() // 帮助信息| void record::VerifyDelete() // 接收用户输入,对删除进行确认,确认返回1,否则返回 0| void record::DeleteNode() // 从链表中删除当前结点| void record::DeleteNodeAtHead() // 删除头结点| void record::DeleteNodeAtEnd() // 删除尾结点| void record::DeleteNodeAtMiddle() // 删除中间结点| void record::DeleteList() // 删除链表,释放空间| void record::SaveFile() // 将链表写入文件| void record::LoadFile() // 从文件中读取数据给链表赋值| void record::ModifyRecord() // 修改记录| void record::UserInput() // 接收用户选择,重试|----------------------------------------------------------------------------*/ /*------------------------------------------------------------------| 根据用户输入的选择调用不同的函数-----------------------------------------------------------------*/void record::UserChoice(int choice){switch(choice){case 1:InsertRecord(); // 增加记录break;case 2:ShowList(); // 显示记录break;case 3:SearchByLastName(); // 搜索记录break;case 4:DeleteRecord(); // 删除记录break;case 5:ModifyRecord(); // 修改记录break;case 6:Help(); // 帮助信息break;case 7:SaveFile(); // 选择退出,并将电话薄资料存入文件if ( head_ptr!=NULL)DeleteList(); // 释放链表结点break;default:cout << "选择无效\n";break;}}/*------------------------------------------------------------------| 插入记录-----------------------------------------------------------------*/void record::InsertRecord(){friend_node * new_ptr; // 定义结点指针new_ptr = new friend_node; // 申请新的结点空间if ( new_ptr!=NULL ) // 如果申请新的结点空间正确{system("cls");cin.ignore(20, '\n'); // 跳过输入流中 20个字符,遇到换行符'\n'就不再跳了(跳过的字符包括终止符'\n')cout << "姓名:";cin.getline(new_ptr->user_name, 20); // 读取从键盘接收到的姓名赋给结点对应的成员cout << "电话号码:";cin.getline(new_ptr->phone_num, 15); // 读取从键盘接收到的电话号码赋给结点对应的成员InsertNode(new_ptr); // 将结点插入到双向链表中}elsecout << "警告:申请存储空间失败,不能创建新结点。
双向链表的名词解释

双向链表的名词解释在计算机科学中,双向链表是一种常用的数据结构,用于存储一系列元素。
与普通的单向链表不同,双向链表每个节点都包含两个指针,分别指向前一个节点和后一个节点,这样每个节点都可以从两个方向遍历。
双向链表的设计使得它在特定场景下具有独特的优势和灵活性。
一、双向链表的结构与操作双向链表通常由一个头节点和一个尾节点构成,这两个节点分别用于指向链表的第一个节点和最后一个节点。
每个节点都包含一个存储元素值的数据域和指向前一个和后一个节点的指针域。
除了常规的插入和删除操作外,双向链表还可以在任意位置插入或删除节点。
1. 插入操作:双向链表的插入操作类似于单向链表,需要通过遍历找到要插入位置的节点,然后将新节点的前后指针指向正确的节点,同时更新前后节点的指针指向新节点。
2. 删除操作:双向链表的删除操作也类似于单向链表,需要找到要删除的节点,然后将其前后节点的指针指向正确的节点,最后释放被删除节点的内存空间。
3. 遍历操作:双向链表的遍历可以从头节点开始,通过后继指针依次遍历到尾节点,或者从尾节点开始,通过前驱指针依次遍历到头节点。
这种双向遍历的方式在某些场景下更加高效,特别是需要反向查找或从尾部开始操作的情况。
二、双向链表的应用场景双向链表由于其特性,使得它在某些特定场景下非常有用,尤其是需要频繁插入、删除或者反向遍历操作的情况。
1. 缓存淘汰算法:LRU(Least Recently Used)是一种常见的缓存淘汰算法,在使用双向链表来实现LRU缓存淘汰策略时,可以通过双向链表的插入和删除操作来维护缓存的顺序,同时利用双向链表的反向遍历来快速定位最近最少使用的缓存项。
2. 字符串编辑器:文本编辑器通常使用双向链表来存储文本内容,在插入或删除字符时,只需要修改前后节点的指针即可完成操作,而无需移动其他字符。
3. 双向队列:双向链表可以用于实现双向队列(Deque),即两端都可以进行插入和删除操作的队列。
数据结构实训心得体会

这次课程设计的心得体会通过实习我的收获如下1、巩固和加深了对数据结构的理解,提高综合运用本课程所学知识的能力。
2、培养了我选用参考书,查阅手册及文献资料的能力。
培养独立思考,深入研究,分析问题、解决问题的能力。
3、通过实际编译系统的分析设计、编程调试,掌握应用软件的分析方法和工程设计方法。
4、通过课程设计,培养了我严肃认真的工作作风,逐步建立正确的生产观念、经济观念和全局观念。
从刚开始得觉得很难,到最后把这个做出来,付出了很多,也得到了很多,以前总以为自己对编程的地方还不行,现在,才发现只要认真做,没有什么不可能。
编程时要认真仔细,出现错误要及时找出并改正,(其中对英语的要求也体现出来了,因为它说明错误的时候都是英语)遇到问题要去查相关的资料。
反复的调试程序,最好是多找几个同学来对你的程序进行调试并听其对你的程序的建议,在他们不知道程序怎么写的时候完全以一个用户的身份来用对你的用户界面做一些建议,正所谓当局者迷旁观者清,把各个注意的问题要想到;同时要形成自己的编写程序与调试程序的风格,从每个细节出发,不放过每个知识点,注意与理论的联系和理论与实践的差别。
另外,要注意符号的使用,注意对字符处理,特别是对指针的使用很容易出错且调试过程是不会报错的,那么我们要始终注意指针的初始化不管它怎么用以免不必要麻烦。
通过近两周的学习与实践,体验了一下离开课堂的学习,也可以理解为一次实践与理论的很好的连接。
特别是本组所做的题目都是课堂上所讲的例子,在实行之的过程中并不是那么容易事让人有一种纸上谈兵的体会,正所谓纸上得来终觉浅绝知此事要躬行。
实训过程中让我们对懂得的知识做了进一步深入了解,让我们的理解与记忆更深刻,对不懂的知识与不清楚的东西也做了一定的了解,也形成了一定的个人做事风格。
通过这次课程设计,让我对一个程序的数据结构有更全面更进一步的认识,根据不同的需求,采用不同的数据存储方式,不一定要用栈,二叉树等高级类型,有时用基本的一维数组,只要运用得当,也能达到相同的效果,甚至更佳,就如这次的课程设计,通过用for的多重循环,舍弃多余的循环,提高了程序的运行效率。
循环链表和双向链表

b.head->next = NULL; //此时,b中已只剩第一个结点(头), 为其置空表标志
return k; //返回结果链表中的元素个数
}
为了进一步说明上述程序,举一个程序运行的例子, 其各次循环的运行结果如图5-6所示
p
7 0 3 2 -9 3 1 5
^
(a)A(x)=p5(x)=7+3x2-9x3+x5,进入循环前
该程序不断比较A链和B链中的一对结点的指数值 (称其为当前结点)。开始时A链和B链中参加比较
的当前结点都是它们的第一个元素。
主循环while结束后,可能出现下列3种情况:①A
链和B链同时被处理完;②只有B链处理完;③只有A
链处理完。 对第一和第二种情况,不需要“善后”处理。对第 三种情况,B链中尚有未被处理完的结点,需将其挂 接在结果链的尾部。循环外的“if(q 不为空)将q
p = p->next; } // if (x==0) … else … q0 = q; q = q->next; delete q0; //将q所指结点从表中删除并释放,令q新指向原所 指的下一个 } // if (p->exp > q->exp ) … else … } //while if (q!=NULL) p0->next = q;
为处理方便,在具体存储多项式时,我们规定:
所存储的多项式已约简,即已合并同类项,不 保留0系数项,各项按指数的升序排列。 (二)多项式加法实现—直接操作链表 为操作方便,我采用带头结点的非循环链表,下面给 出一个例子说明多项式的这种表示法。
设有一个一元5次多项式: P5(x)=7+3x-9x3+x5
C#数据结构之双向链表(DbLinkList)实例详解

C#数据结构之双向链表(DbLinkList)实例详解本⽂实例讲述了C#数据结构之双向链表(DbLinkList)。
分享给⼤家供⼤家参考,具体如下:这是继上⼀篇《》的继续,对于双向链接,节点上除了Next属性外,还要有Prev属性⽤来指向前⼀个节点,DbNode定义如下:namespace 线性表{public class DbNode<T>{private T data;private DbNode<T> prev;private DbNode<T> next;public DbNode(T data, DbNode<T> next,DbNode<T> prev){this.data = data;this.next = next;this.prev = prev;}public DbNode(T data, DbNode<T> next){this.data = data;this.next = next;this.prev = null;}public DbNode(DbNode<T> next){this.data = default(T);this.next = next;this.prev = null;}public DbNode(T data){this.data = data;this.next = null;this.prev = null;}public DbNode(){data = default(T);next = null;prev = null;}public T Data{set { this.data = value; }get { return this.data; }}public DbNode<T> Prev{get { return prev; }set { prev = value; }}public DbNode<T> Next{get { return next; }set { next = value; }}}}双链表的插⼊操作要稍微复杂⼀点,⽰意图如下:同样对于删除操作,也要额外处理prev指向完整实现DbLinkList<T>:namespace 线性表{public class DbLinkList<T> : IListDS<T> {private DbNode<T> head;public DbNode<T> Head{get { return head; }set { head = value; }}public DbLinkList(){head = null;}/// <summary>/// 类索引器/// </summary>/// <param name="index"></param>/// <returns></returns>public T this[int index]{get{return this.GetItemAt(index);}}/// <summary>/// 返回单链表的长度/// </summary>/// <returns></returns>public int Count(){DbNode<T> p = head;int len = 0;while (p != null){len++;p = p.Next;}return len;}/// <summary>/// 清空/// </summary>public void Clear(){head = null;}/// <summary>/// 是否为空/// </summary>/// <returns></returns>public bool IsEmpty(){return head == null;}/// <summary>/// 在最后附加元素/// </summary>/// <param name="item"></param>public void Append(T item){DbNode<T> d = new DbNode<T>(item); DbNode<T> n = new DbNode<T>();if (head == null){head = d;return;}n = head;while (n.Next != null){n = n.Next;}n.Next = d;//前插public void InsertBefore(T item, int i){if (IsEmpty() || i < 0){Console.WriteLine("List is empty or Position is error!"); return;}//在最开头插⼊if (i == 0){DbNode<T> q = new DbNode<T>(item);q.Next = head;//把"头"改成第⼆个元素head.Prev = q;head = q;//把⾃⼰设置为"头"return;}DbNode<T> n = head;DbNode<T> d = new DbNode<T>();int j = 0;//找到位置i的前⼀个元素dwhile (n.Next != null && j < i){d = n;n = n.Next;j++;}if (n.Next == null) //说明是在最后节点插⼊(即追加){DbNode<T> q = new DbNode<T>(item);n.Next = q;q.Prev = n;q.Next = null;}else{if (j == i){DbNode<T> q = new DbNode<T>(item);d.Next = q;q.Prev = d;q.Next = n;n.Prev = q;}}}/// <summary>/// 在位置i后插⼊元素item/// </summary>/// <param name="item"></param>/// <param name="i"></param>public void InsertAfter(T item, int i){if (IsEmpty() || i < 0){Console.WriteLine("List is empty or Position is error!"); return;}if (i == 0){DbNode<T> q = new DbNode<T>(item);q.Next = head.Next;head.Next.Prev = q;head.Next = q;q.Prev = head;return;}DbNode<T> p = head;int j = 0;while (p != null && j < i){p = p.Next;j++;}DbNode<T> q = new DbNode<T>(item);q.Next = p.Next;if (p.Next != null){p.Next.Prev = q;}p.Next = q;q.Prev = p;}else{Console.WriteLine("Position is error!");}}/// <summary>/// 删除位置i的元素/// </summary>/// <param name="i"></param>/// <returns></returns>public T RemoveAt(int i){if (IsEmpty() || i < 0){Console.WriteLine("Link is empty or Position is error!"); return default(T);}DbNode<T> q = new DbNode<T>();if (i == 0){q = head;head = head.Next;head.Prev = null;return q.Data;}DbNode<T> p = head;int j = 0;while (p.Next != null && j < i){j++;q = p;p = p.Next;}if (j == i){p.Next.Prev = q;q.Next = p.Next;return p.Data;}else{Console.WriteLine("The node is not exist!");return default(T);}}/// <summary>/// 获取指定位置的元素/// </summary>/// <param name="i"></param>/// <returns></returns>public T GetItemAt(int i){if (IsEmpty()){Console.WriteLine("List is empty!");return default(T);}DbNode<T> p = new DbNode<T>();p = head;if (i == 0){return p.Data;}int j = 0;while (p.Next != null && j < i)j++;p = p.Next;}if (j == i){return p.Data;}else{Console.WriteLine("The node is not exist!");return default(T);}}//按元素值查找索引public int IndexOf(T value){if (IsEmpty()){Console.WriteLine("List is Empty!");return -1;}DbNode<T> p = new DbNode<T>();p = head;int i = 0;while (!p.Data.Equals(value) && p.Next != null){p = p.Next;i++;}return i;}/// <summary>/// 元素反转/// </summary>public void Reverse(){DbLinkList<T> result = new DbLinkList<T>();DbNode<T> t = this.head;result.Head = new DbNode<T>(t.Data);t = t.Next;//(把当前链接的元素从head开始遍历,逐个插⼊到另⼀个空链表中,这样得到的新链表正好元素顺序跟原链表是相反的) while (t!=null){result.InsertBefore(t.Data, 0);t = t.Next;}this.head = result.head;//将原链表直接挂到"反转后的链表"上result = null;//显式清空原链表的引⽤,以便让GC能直接回收}//得到某个指定的节点(为了下⾯测试从后向前遍历)private DbNode<T> GetNodeAt(int i){if (IsEmpty()){Console.WriteLine("List is empty!");return null;}DbNode<T> p = new DbNode<T>();p = head;if (i == 0){return p;}int j = 0;while (p.Next != null && j < i){j++;p = p.Next;}if (j == i){return p;}else{Console.WriteLine("The node is not exist!");}}/// <summary>/// 测试⽤prev属性从后⾯开始遍历/// </summary>/// <returns></returns>public string TestPrevErgodic(){DbNode<T> tail = GetNodeAt(Count() - 1);StringBuilder sb = new StringBuilder();sb.Append(tail.Data.ToString() + ",");while (tail.Prev != null){sb.Append(tail.Prev.Data.ToString() + ",");tail = tail.Prev;}return sb.ToString().TrimEnd(',');}public override string ToString(){StringBuilder sb = new StringBuilder();DbNode<T> n = this.head;sb.Append(n.Data.ToString() + ",");while (n.Next != null){sb.Append(n.Next.Data.ToString() + ",");n = n.Next;}return sb.ToString().TrimEnd(',');}}}测试代码⽚段:Console.WriteLine("-------------------------------------");Console.WriteLine("双链表测试开始...");DbLinkList<string> dblink = new DbLinkList<string>();dblink.Head = new DbNode<string>("x");dblink.InsertBefore("w", 0);dblink.InsertBefore("v", 0);dblink.Append("y");dblink.InsertBefore("z", dblink.Count());Console.WriteLine(dblink.Count());//5Console.WriteLine(dblink.ToString());//v,w,x,y,zConsole.WriteLine(dblink[1]);//wConsole.WriteLine(dblink[0]);//vConsole.WriteLine(dblink[4]);//zConsole.WriteLine(dblink.IndexOf("z"));//4Console.WriteLine(dblink.RemoveAt(2));//xConsole.WriteLine(dblink.ToString());//v,w,y,zdblink.InsertBefore("x", 2);Console.WriteLine(dblink.ToString());//v,w,x,y,zConsole.WriteLine(dblink.GetItemAt(2));//xdblink.Reverse();Console.WriteLine(dblink.ToString());//z,y,x,w,vdblink.InsertAfter("1", 0);dblink.InsertAfter("2", 1);dblink.InsertAfter("6", 5);dblink.InsertAfter("8", 7);dblink.InsertAfter("A", 10);//Position is error!Console.WriteLine(dblink.ToString()); //z,1,2,y,x,w,6,v,8string _tail = dblink.GetItemAt(dblink.Count()-1);Console.WriteLine(_tail);Console.WriteLine(dblink.TestPrevErgodic());//8Console.ReadKey(); //8,v,6,w,x,y,2,1,z当然从上⾯的测试代码中,似乎并不能看出双链表的优点,双链表的好处在于,如果需要在链表中,需要通过某个节点得到它的前驱节点时,双链表直接⽤prev属性就能找到;⽽单链表要做到这⼀点,必须再次从Head节点开始⼀个⼀个⽤Next向下找,这样时间复杂度从O(n)降到O(1),显然更有效率。
通讯录链表课程设计

通讯录链表课程设计一、教学目标本节课的学习目标包括知识目标、技能目标和情感态度价值观目标。
知识目标要求学生掌握通讯录链表的基本概念、结构和实现方法。
技能目标要求学生能够运用所学的知识,独立设计和实现一个简单的通讯录链表程序。
情感态度价值观目标要求学生培养对计算机科学和编程的兴趣,提高解决问题的能力,培养团队合作的精神。
教学内容要与学生的实际水平相适应,注重培养学生的动手能力和创新能力。
在教学过程中,要关注学生的个体差异,因材施教,使学生在掌握基础知识的同时,提高自己的综合素质。
二、教学内容本节课的教学内容主要包括通讯录链表的基本概念、结构和实现方法。
首先,介绍通讯录链表的概念,让学生了解通讯录链表的作用和应用。
然后,讲解通讯录链表的结构,包括节点结构、头节点和尾节点的定义。
接下来,介绍通讯录链表的实现方法,包括节点的创建、添加、删除和查找等操作。
在教学过程中,要结合实例进行讲解,让学生更好地理解通讯录链表的原理和实现方法。
同时,要注重实践操作,让学生通过动手实践,加深对通讯录链表的理解。
三、教学方法本节课的教学方法采用讲授法、讨论法和实验法相结合的方式。
首先,通过讲授法向学生传授通讯录链表的基本概念和原理。
然后,通过讨论法引导学生探讨通讯录链表的实现方法,激发学生的思考和创新。
最后,通过实验法让学生动手实践,培养学生的实际操作能力。
在教学过程中,要注意调动学生的积极性,鼓励学生提问和发表自己的观点。
同时,要关注学生的个体差异,因材施教,使学生在掌握基础知识的同时,提高自己的综合素质。
四、教学资源本节课的教学资源包括教材、参考书、多媒体资料和实验设备。
教材和参考书用于为学生提供理论知识的学习,多媒体资料用于辅助教学,使学生更直观地了解通讯录链表的原理和实现方法。
实验设备用于让学生动手实践,培养实际操作能力。
在教学过程中,要充分利用教学资源,为学生提供丰富多样的学习途径。
同时,要注意教学资源的更新和维护,确保教学资源的质量和效果。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
//node.h#include<iostream.h>#include<fstream.h>#include<string.h>#include<stdlib.h>#include<iomanip.h>struct data //数据{char name[20]; //姓名char tel[20]; //电话int age; //年龄};class node //节点{friend class link; //友远类private:data person; //数据node * next;node * pre;public:void show() //显示数据信息{cout<<"姓名:"<<setw(20)<<<<endl;cout<<"电话:"<<setw(20)<<person.tel<<endl;cout<<"年龄:"<<setw(3)<<person.age<<endl<<endl;}node(char*name0="",char*tel0="",int age0=0) //构造函数{strcpy(,name0);strcpy(person.tel,tel0);person.age=age0;next=NULL;pre=NULL;}node(node&n) ////拷贝构造{strcpy(,);strcpy(person.tel,n.person.tel);person.age=n.person.age;}};class link{ //双向链表node * head; //头指针node * rear; //尾指针node * findbyname(char*name0,node *temp ) //查找姓名返回地址{temp=head;if(!head) //空链表{cout<<"通讯录中没有信息"<<endl<<endl;return NULL;}node * p=head;while(p){if(strcmp(p->,name0)==0) //已找到return p;p=p->next;}while(temp){if(Cmpstr(temp->,name0)){cout<<endl<<"符合条件的记录,如下:"<<endl;temp->show();}temp=temp->next;}//if(temp)// cout<<"查无此人"<<endl<<endl;//未找到}return temp;}node * findbyname(char*name0) //查找姓名返回地址{if(!head) //空链表{cout<<"通讯录中没有信息"<<endl<<endl;return NULL;}node * p=head;while(p){if(strcmp(p->,name0)==0) //已找到return p;p=p->next;}if(!p)cout<<"查无此人"<<endl<<endl;return NULL;//未找到}int length() //返回链表长度{if(!head)return 0;node*p;int n=1;p=head;if(p->next){p=p->next;n++;}return n;}node * findbynum(int num) //根据序号查找{int l=length(); //l为总长if(!head) //空链表{cout<<"通讯录中没有信息"<<endl<<endl;return NULL;}if(num>l) //数据越界{cout<<"通讯录里没有"<<num<<"条信息"<<endl<<endl;return NULL;}node * p=head;while(--num)p=p->next;return p; //返回指针}void change(node*p)//修改对应指针信息{char tel0[20];int age0,cho;cout<<"请输入新的电话号码"<<endl;cin>>tel0;cout<<"请输入新的年龄"<<endl;cin>>age0;cout<<"姓名:"<<p-><<endl;cout<<"原电话号码:"<<setw(20)<<p->person.tel<<endl;cout<<"原年龄:"<<setw(3)<<p->person.age<<endl<<endl;cout<<"新电话号码:"<<setw(20)<<tel0<<endl;cout<<"新年龄:"<<setw(3)<<age0<<endl<<endl;cout<<"1.确认 2.取消"<<endl;cin>>cho;if(cho==1){strcpy(p->person.tel,tel0);p->person.age=age0;cout<<"已修改成功"<<endl;}}void del(node *p) //删除一个节点{if(!head) //空链表{cout<<"通讯录中没有信息"<<endl<<endl;return ;}if(p==head) //删除头结点{p->next->pre=NULL;head=p->next;delete p;return;}if(p==rear) //删除尾节点{p->pre->next=NULL;rear=p->pre;delete p;return;}p->next->pre=p->pre; //删除中间节点p->pre->next=p->next;delete p;}void delall() //删除整个链表{node*p;while(head){p=head;head=head->next;delete p;}head=rear=NULL;}public:link() //构造函数{head=rear=NULL;}~link(){ //析构函数,同时释放链表空间delall();}node * cinnode() //从键盘输入生成一个节点{char name[20],tel[20];int age;node*p;p=new node;cout<<"请输入姓名"<<endl;cin>>name;cout<<"请输入电话号码"<<endl;cin>>tel;cout<<"请输入年龄"<<endl;cin>>age;*p=node(name,tel,age);return p;}void insert(node *p) //将节点插入链表{node *p1,*p2;if(head==0) //空链表{p->next=0;p->pre=0;head=rear=p;return;}if(strcmp(head->,p->)>0){p->next=head;head->pre=p;p->pre=0;head=p;return;}if(strcmp(rear->,p->)<0){p->pre=rear;rear->next=p;p->next=0;rear=p;return ;}p1=p2=head;while(strcmp(p2->,p->)<0){p1=p2;p2=p2->next;}p->next=p2; //插入链表中间p2->pre=p;p1->next=p;p->pre=p1;}void showfromhead() //从前向后输出链表{if(!head) //空链表cout<<"通讯录无信息"<<endl;else{int c=0;node *p;p=head;while(p){p->show(); //调用函数显示信息p=p->next;c++;//if(c%5==0) //控制每输出 5 个暂停一次//system("pause");}cout<<"所有信息输出完成"<<endl;}}void showfromrear() //从后向前输出链表{if(!rear)cout<<"通讯录无信息"<<endl;else{int c=0;node*p;p=rear;while(p){p->show();p=p->pre;c++;if(c%6==0)system("pause");}cout<<"所有信息输出完成"<<endl;}}void showbyname(node *temp) //根据姓名显示信息{char name[20];cout<<"请输入欲查找的姓名"<<endl;cin>>name;node *p;p=findbyname(name,temp); //查找姓名所对应的指针if(p)p->show();}void changebyname() //根据姓名修改信息{char name[20];cout<<"请输入欲修改的姓名"<<endl;cin>>name;node*p;p=findbyname(name);if(p)change(p);}void delbyname() //根据姓名删除信息{char name[20];if(!head) //空链表{cout<<"通讯录中没有信息"<<endl<<endl;return ;cout<<"请输入欲删除的姓名"<<endl;cin>>name;node*p;p=findbyname(name);if(p)del(p);cout<<"已删除选定信息"<<endl;}void showbynum() //根据序号显示信息{int num;if(!head) //空链表{cout<<"通讯录中没有信息"<<endl<<endl;return ;}cout<<"请输入欲查找编号"<<endl;cin>>num;node*p;p=findbynum(num); //根据序号查找指针if(p)p->show();}void delbynum() //根据序号删除信息{int num;if(!head) //空链表{cout<<"通讯录中没有信息"<<endl<<endl;return ;}cout<<"请输入欲删除编号"<<endl;cin>>num;node*p;p=findbynum(num);if(p)del(p);cout<<"已删除选定信息"<<endl;}void changebynum() //根据序号修改信息{int num;if(!head) //空链表cout<<"通讯录中没有信息"<<endl<<endl;return;}cout<<"请输入欲修改编号"<<endl;cin>>num;node*p;p=findbynum(num);if(p)change(p);}void inputnode()//从文件读入{char filename[30];cout<<"输入数据源文件名"<<endl;cin>>filename;ifstream fin(filename,ios::in|ios::nocreate);if(!fin){cout<<"无法打开指定文件"<<endl;exit(1);}char name[20],tel[20];int age;node *p;while(fin>>name){fin>>tel>>age;p=new node(name,tel,age);insert(p);}fin.close();}void outfromhead() //顺序输出至文件{char filename[30];cout<<"输入数据目标文件名"<<endl;cin>>filename;ofstream fout(filename);if(!fout){cout<<"无法打开指定文件"<<endl;exit(1);}if(!head)fout<<"通讯录无信息"<<endl;else{node*p;p=head;while(p){fout<<"姓名:"<<setw(20)<<p-><<endl;fout<<"电话:"<<setw(20)<<p->person.tel<<endl;fout<<"年龄:"<<setw(3)<<p->person.age<<endl<<endl;;p=p->next;}cout<<"所有信息输出完成"<<endl;}}void outfromrear() //逆序输出至文件{char filename[30];cout<<"输入数据目标文件名"<<endl;cin>>filename;ofstream fout(filename);if(!fout){cout<<"无法打开指定文件"<<endl;exit(1);}if(!rear)fout<<"通讯录无信息"<<endl;else{node*p;p=rear;while(p){fout<<"姓名:"<<setw(20)<<p-><<endl;fout<<"电话:"<<setw(20)<<p->person.tel<<endl;fout<<"年龄:"<<setw(3)<<p->person.age<<endl<<endl;;p=p->pre;}cout<<"所有信息输出完成"<<endl;}}bool Cmpstr(char*name_node,char*name_search)//传统型字符串比较函数,支持通配符*,?及大小写转换,name_node等于name_search时,返回true{if(name_search[0]=='*') //通配符*,通配任意字符串,返回truereturn true;char name1[20],name2[20];//避免改变原结点中的信息strncpy(name1,name_node,20);strncpy(name2,name_search,20);int size1=strlen(name1),size2=strlen(name_search);for(int i=0;i<size2;i++){if(name2[i]>='A'&&name2[i]<='Z')//大写全部转换为小写,以便于比较,人性化处理name2[i]+=32;}for(int i1=0;i1<size1;i1++){if(name1[i1]>='A'&&name1[i1]<='Z')//大写全部转换为小写,以便于比较,人性化处理name1[i1]+=32;}for(int i2=0;i2<size1;i2++){if(name_search[i2]=='*')//通配符*,通配任意字符串,{for(int j=0;j<i2;j++){if(name1[j]!=name2[j])return false;}return true;}}if(size1!=size2)//不等长时,即两字符串不相等,返回false{return false;}for(int i3=0;i3<size1;i3++){if(name2[i3]=='?')//通配符‘?’,通配任一字符continue;if(name1[i3]!=name2[i3])return false;}return true;}};//main.cpp#include "node.h"void main();char buffer[100];void show_data(link &a){char c;cout<<"查看全部数据"<<endl;cout<<"1.顺序 2.逆序"<<endl;cin>>c;if(c=='1'){a.showfromhead();system("pause");cout<<endl<<endl;system("cls");return;}if(c=='2'){a.showfromrear();system("pause");cout<<endl<<endl;system("cls");return;}if(c!='1'&&c!='2'){cout<<"input error"<<endl;system("pause");cout<<endl<<endl;system("cls");void show_data(link &a);return;}};void delet_data(link &a){char c;cout<<"删除数据"<<endl;cout<<"1.根据序号删除数据 2.根据姓名删除数据"<<endl;cin>>c;if(c=='1'){a.delbynum();system("pause");cout<<endl<<endl;system("cls");}if(c=='2'){a.delbyname();system("pause");cout<<endl<<endl;system("cls");}if(c!='1'&&c!='2'){cout<<"input error"<<endl;system("pause");cout<<endl<<endl;system("cls");void delet_data(link &a);}};void insert_data(link &a){cout<<"添加数据"<<endl;a.insert(a.cinnode());system("pause");cout<<endl<<endl;system("cls");};void updata(link &a){char c;cout<<"修改数据"<<endl;cout<<"1.根据序号修改数据 2.根据姓名修改数据"<<endl;cin>>c;if(c=='1'){a.changebynum();system("pause");cout<<endl<<endl;system("cls");}if(c=='2'){a.changebyname();system("pause");cout<<endl<<endl;system("cls");}if(c!='1'&&c!='2'){cout<<"input error"<<endl;system("pause");cout<<endl<<endl;system("cls");void updata(link &a);}};void search_data(link &a){char c;node *temp;cout<<"查找数据"<<endl;cout<<"1.根据序号查找数据 2.根据姓名查找数据(支持*与?的通配)"<<endl;cin>>c;if(c=='1'){a.showbynum();system("pause");cout<<endl<<endl;system("cls");}if(c=='2'){a.showbyname(temp);system("pause");cout<<endl<<endl;system("cls");}if(c!='1'&&c!='2'){cout<<"input error"<<endl;system("pause");cout<<endl<<endl;system("cls");void search_data(link &a);}};void output_data(link &a){char c;cout<<"将数据输出至文件"<<endl;cout<<"1.升序 2.降序"<<endl;cin>>c;if(c=='1'){a.outfromhead();system("pause");cout<<endl<<endl;system("cls");}if(c=='2'){a.outfromrear();system("pause");cout<<endl<<endl;system("cls");}if(c!='1'&&c!='2'){cout<<"input error"<<endl;system("pause");cout<<endl<<endl;system("cls");void output_data(link &a);}};link a;void menu(){char c;cout<<"\t\t 通讯录管理系统"<<endl;cout<<"1.查看全部数据"<<endl;cout<<"2.删除数据"<<endl;cout<<"3.添加数据"<<endl;cout<<"4.修改数据"<<endl;cout<<"5.查找数据"<<endl;cout<<"6.从文件输入数据"<<endl;cout<<"7.将数据输出至文件"<<endl;cout<<"8.退出"<<endl<<endl;cout<<"请输入您需要的功能"<<endl;cin>>c;switch(c){case '1':show_data(a);menu();break;case '2':delet_data(a);menu();break;case '3':insert_data(a);menu();break;case '4':updata(a);menu();break;case '5':search_data(a);menu();break;case '6':cout<<"从文件输入数据"<<endl;a.inputnode();system("pause");cout<<endl<<endl;system("cls");menu();break;case '7':output_data(a);menu();break;case '8':cout<<"谢谢使用"<<endl;return ;default:{cin.clear();cin.getline(buffer,100);cout<<"input error "<<endl;system("pause");system("cls");menu();}}return;}void main() //显示菜单,并调用对应函数{menu();}。