双向链表(比单项链表好用)
之前写了一份但项链表的学生信息管理的博客,今天又学到了双向链表,所以用双向链表写了一份代码(输入暂时只设置了name项,输出增加了时间),想要其他信息的,可以修改结构体的内容和输入输出对应的内容即可。
本文与原文有很大的不同:
本文中,
链表结点数量无需提前指定,随着内容输入,可以动态增加,不存在输入”溢出“,影响之后的运行输入的问题;
增加了时间函数调用和转换的部分;
双项链表传递参数的时候,会更简洁(使用的参数少)---个人感觉,可能是我之前的单向链表没设计好;
***在指定位置插入,会优先匹配
***如果已经存在 则在其后面开始插入
***如果不存在,那么从头向尾遍历,比较name大小,在第一个比要查入的name大的前面插入
***插入的时候因为调用的是创建or增加的函数,所以插入会再次输入插入name,
***插入数量不限,并且 exit退出
ps:就不上图了,想看效果的,自己复制代码试试吧!
敲黑板:
时间的调用及输出
/*获取时间 年月日时分秒*/
void qiandao_t(int *ptim)
{
int t1,t2,t3;//分别代表 时间 时 分 秒
int td1,td2,td3;//分别代表 时间 时 分 秒
/*获取时间*/
time_t t;//必备格式 1
struct tm * lt;//必备格式 2
time (&t);//获取Unix时间戳。//必备格式 3
lt = localtime (&t);//转为时间结构。//必备格式 4
t1=lt->tm_hour,t2= lt->tm_min, t3=lt->tm_sec;
td1=lt->tm_year+1900,td2= lt->tm_mon+1, td3=lt->tm_mday;
/*获取的时间数值存入数组*/
ptim[0]=td1;//年
ptim[1]=td2;//月
ptim[2]=td3;//日
ptim[3]=t1;//时
ptim[4]=t2;//分
ptim[5]=t3;//秒
}
结构体:
struct birthday
{
int year;
int month;
int day;
};
struct student
{
char name[10];
int sex;
struct birthday bir;
int q_time[6];
struct student *front;//前结点
struct student *back;//后结点
};
输入部分
scanf("%s",ex); //把需要输入的内容按格式加进来
输出部分
printf("\n%s ",p->name);//输出名字
/*输出其他内容,按格式添加在这里即可*/
/*输出时间*/
printf("签到时间:%d年%d月%d日%d时%d分%d秒\n", p->q_time[0],\
p->q_time[1],p->q_time[2],p->q_time[3],p->q_time[4],p->q_time[5]);
代码如下:
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "windows.h"
#include "time.h"
/*结构体定义 出生年月*/
struct birthday
{
int year;
int month;
int day;
};
/*结构体定义*/
struct student
{
char name[10];//姓名
int Gender;//性别
struct birthday bir;/*结构体嵌套*/
int q_time[6];// 时间
struct student *front;//前结点
struct student *back;//后结点
};
/*函数声明*/
int mean_l();//循环菜单
void qiandao_t(int *ptim); //获取时间函数
void input_creact_lian(struct student *head);//新建or增加结点函数
void output_l(struct student *head);//输出函数
void del_l(struct student *head);//删除指定结点函数
void Duplicate_removal(struct student *head);//去除重复结点函数
/*创建链表*/
void input_creact_lian(struct student *head)
{
int i=0;
char ex[10];//接收输入的姓名
struct student *q;
q=head->front;
printf("\n****************增加新的结点***************\n");
printf("\t 输入 exit 退出!\n\n");
while(1)
{
scanf("%s",ex);
if(strcmp(ex,"exit")==0) break;//退出循环条件
struct student *p;
if((p=(struct student *)malloc((sizeof(struct student))))==NULL)
{
printf(" Sorry 分配内存失败。。。");
exit(0);
}
memset(p,0,sizeof(struct student));
q->back=p;
p->front=q;
q=p;
q->back=NULL;
strcpy(q->name,ex);
qiandao_t(p->q_time);
i++;
}
q->back=head;/*链接头结点 */
head->front=q;/*链接尾结点 */
printf("\n************恭喜成功创建 %d 个结点***********\n\n",i);//输出结点个数(不含头结点)
}
/*函数输出数据*/
void output_l(struct student *head)
{
int i=0;
if(i==0)printf("\n\n****************最新内容如下******************\n");
struct student *p;
/*从头结点向后遍历---正序输出*/
p=head->back;
while(p!=head)
{
printf("\n%s 签到时间:",p->name);
printf("%d年%d月%d日%d时%d分%d秒\n", p->q_time[0],\
p->q_time[1],p->q_time[2],p->q_time[3],p->q_time[4],p->q_time[5]);
p=p->back;
i++;
}
/*从尾结点向前遍历---逆序输出*/
// p=head->front;
// while(p!=head)
// {
// printf("\n%s 签到时间:",p->name);
// printf("%d年%d月%d日%d时%d分%d秒\n", p->q_time[0],\
// p->q_time[1],p->q_time[2],p->q_time[3],p->q_time[4],p->q_time[5]);
// p=p->front;
// }
printf("\n***************共有 %d 条信息******************\n\n",i);
}
/*函数:去除重复结点*/
void Duplicate_removal(struct student *head)
{
printf("\n***********即将依据结点name去除重复结点*******\n\n");
system("pause");
printf("\n");
int i=0;//删除计数器
struct student *p,*q,*dm;
/*从头结点向后遍历---正序*/
dm=head->back;
while(dm!=head)
{
p=dm->back;
while(p!=head)
{
if(strcmp(p->name,dm->name)==0)
{
q=p;
p=p->back;
if(i++==0)printf("\n\n****************删除了如下结点****************\n");
printf("\n%s 签到时间:",q->name);
printf("%d年%d月%d日%d时%d分%d秒\n", q->q_time[0],\
q->q_time[1],q->q_time[2],q->q_time[3],q->q_time[4],q->q_time[5]);
/*舍弃结点*/
q->front->back=q->back;
q->back->front=q->front;
free(q);
}
else p=p->back;
}
dm=dm->back;
}
printf("\n**************已经完成去重任务*****************\n\n");
}
/*函数:删除指定结点*/
void del_l(struct student *head)
{
char ex[10];
printf("\n请输入要删除的name: ");
scanf("%s",ex);
struct student *p;
/*从头结点向后遍历---正序*/
p=head->back;
while(p!=head)
{
if(strcmp(p->name,ex)==0)
{
q=p;
p=p->back;
printf("\n****************删除了如下结点****************\n");
printf("\n%s 签到时间:",q->name);
printf("%d年%d月%d日%d时%d分%d秒\n", q->q_time[0],\
q->q_time[1],q->q_time[2],q->q_time[3],q->q_time[4],q->q_time[5]);
/*舍弃结点*/
q->front->back=q->back;
q->back->front=q->front;
free(q);
}
else p=p->back;
}
printf("\n****************已经完成删除任务***************\n\n");
}
/*在指定位置插入结点*/
void add_l(struct student *head)
{
char ex[10];
printf("\n请输入要插入的name: ");
scanf("%s",ex);
struct student *p,*q;
/*从头结点向后遍历---正序*/
p=head->back;
while(p!=head)
{
if(strcmp(p->name,ex)==0) //存在 在后面插入
{
p=p->back;
input_creact_lian(p);
break;
}
if(strcmp(p->name,ex)>0)//不存在 找到第一个比插入值大的 在前面插入
{
input_creact_lian(p);
break;
}
else p=p->back;
}
}
/*获取时间年月日时分秒*/
void qiandao_t(int *ptim)
{
int t1,t2,t3;//分别代表 时间 时 分 秒
int td1,td2,td3;//分别代表 时间 时 分 秒
/*获取时间*/
time_t t;
struct tm * lt;
time (&t);//获取Unix时间戳。
lt = localtime (&t);//转为时间结构。
t1=lt->tm_hour,t2= lt->tm_min, t3=lt->tm_sec;
td1=lt->tm_year+1900,td2= lt->tm_mon+1, td3=lt->tm_mday;
/*获取的时间数值存入数组*/
ptim[0]=td1;//年
ptim[1]=td2;//月
ptim[2]=td3;//日
ptim[3]=t1;//时
ptim[4]=t2;//分
ptim[5]=t3;//秒
}
/*循环目录*/
int mean_l(struct student *head)
{
printf("【0】退出\n【1】新建or增加结点\n【2】插入指定结点\n【3】去除重复结点\n");
printf("【4】删除指定结点\n【5】查看现有结点\n\n");
char c;
printf(" ");
c=getchar();
printf("***\n");
int i=c-'0';
switch(i)
{
case 0 : return 0; break;
case 1 : input_creact_lian(head); break;
case 2 : add_l(head); break;
case 3 : Duplicate_removal(head); break;
case 4 : del_l(head); break;
case 5 : output_l(head); break;
default :
printf("****** Err 输入错误。。。*******\n\n");
}
fflush(stdin);
mean_l(head);
}
/*主函数*/
int main(void)
{
printf("\n************学生签到信息表*************\n\n");
struct student *head;//创建头结点
if((head=(struct student *)malloc((sizeof(struct student))))==NULL)
{
printf(" Sorry 分配内存失败。。。");
exit(0);
}
memset(head,0,sizeof(struct student));//初始化头结点
head->front=head->back=head;//头结点自循环
mean_l(head);
system("pause");
}
VS 2017 中代码略有不同
如下:
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "windows.h"
#include "time.h"
/*结构体定义 出生年月*/
struct birthday
{
int year;
int month;
int day;
};
/*结构体定义*/
struct student
{
char name[10];//姓名
int Gender;//性别
struct birthday bir;/*结构体嵌套*/
int q_time[6];// 时间
struct student *front;//前结点
struct student *back;//后结点
};
/*函数声明*/
int mean_l();//循环菜单
void qiandao_t(int *ptim); //获取时间函数
void input_creact_lian(struct student *head);//新建or增加结点函数
void output_l(struct student *head);//输出函数
void del_l(struct student *head);//删除指定结点函数
void Duplicate_removal(struct student *head);//去除重复结点函数
/*创建链表*/
void input_creact_lian(struct student *head)
{
int i = 0;
char ex[10];//接收输入的姓名
struct student *q;
q = head->front;
printf("\n****************增加新的结点***************\n");
printf("\t 输入 exit 退出!\n\n");
while (1)
{
scanf("%s", ex);
if (strcmp(ex, "exit") == 0) break;//退出循环条件
struct student *p;
if ((p = (struct student *)malloc((sizeof(struct student)))) == NULL)
{
printf(" Sorry 分配内存失败。。。");
exit(0);
}
memset(p, 0, sizeof(struct student));
q->back = p;
p->front = q;
q = p;
q->back = NULL;
strcpy(q->name, ex);
qiandao_t(p->q_time);
i++;
}
q->back = head;/*链接头结点 */
head->front = q;/*链接尾结点 */
printf("\n************恭喜成功创建 %d 个结点***********\n\n", i);//输出结点个数(不含头结点)
}
/*函数输出数据*/
void output_l(struct student *head)
{
int i = 0;
if (i == 0)printf("\n\n****************最新内容如下******************\n");
struct student *p;
/*从头结点向后遍历---正序输出*/
p = head->back;
while (p != head)
{
printf("\n%s 签到时间:", p->name);
printf("%d年%d月%d日%d时%d分%d秒\n", p->q_time[0], \
p->q_time[1], p->q_time[2], p->q_time[3], p->q_time[4], p->q_time[5]);
p = p->back;
i++;
}
/*从尾结点向前遍历---逆序输出*/
// p=head->front;
// while(p!=head)
// {
// printf("\n%s 签到时间:",p->name);
// printf("%d年%d月%d日%d时%d分%d秒\n", p->q_time[0],\
// p->q_time[1],p->q_time[2],p->q_time[3],p->q_time[4],p->q_time[5]);
// p=p->front;
// }
printf("\n***************共有 %d 条信息******************\n\n", i);
}
/*函数:去除重复结点*/
void Duplicate_removal(struct student *head)
{
printf("\n***********即将依据结点name去除重复结点*******\n\n");
system("pause");
printf("\n");
int i = 0;//删除计数器
struct student *p, *q, *dm;
/*从头结点向后遍历---正序*/
dm = head->back;
while (dm != head)
{
p = dm->back;
while (p != head)
{
if (strcmp(p->name, dm->name) == 0)
{
q = p;
p = p->back;
if (i++ == 0)printf("\n\n****************删除了如下结点****************\n");
printf("\n%s 签到时间:", q->name);
printf("%d年%d月%d日%d时%d分%d秒\n", q->q_time[0], \
q->q_time[1], q->q_time[2], q->q_time[3], q->q_time[4], q->q_time[5]);
/*舍弃结点*/
q->front->back = q->back;
q->back->front = q->front;
free(q);
}
else p = p->back;
}
dm = dm->back;
}
printf("\n**************已经完成去重任务*****************\n\n");
}
/*函数:删除指定结点*/
void del_l(struct student *head)
{
char ex[10];
printf("\n请输入要删除的name: ");
scanf("%s", ex);
struct student *p, *q;
/*从头结点向后遍历---正序*/
p = head->back;
while (p != head)
{
if (strcmp(p->name, ex) == 0)
{
q = p;
p = p->back;
printf("\n****************删除了如下结点****************\n");
printf("\n%s 签到时间:", q->name);
printf("%d年%d月%d日%d时%d分%d秒\n", q->q_time[0], \
q->q_time[1], q->q_time[2], q->q_time[3], q->q_time[4], q->q_time[5]);
/*舍弃结点*/
q->front->back = q->back;
q->back->front = q->front;
free(q);
}
else p = p->back;
}
printf("\n****************已经完成删除任务***************\n\n");
}
/*在指定位置插入结点*/
void add_l(struct student *head)
{
char ex[10];
printf("\n请输入要插入的name: ");
scanf("%s", ex);
struct student *p;
/*从头结点向后遍历---正序*/
p = head->back;
while (p != head)
{
if (strcmp(p->name, ex) == 0) //存在 在后面插入
{
p = p->back;
input_creact_lian(p);
break;
}
if (strcmp(p->name, ex) > 0)//不存在 找到第一个比插入值大的 在前面插入
{
input_creact_lian(p);
break;
}
else p = p->back;
}
}
/*获取时间年月日时分秒*/
void qiandao_t(int *ptim)
{
int t1, t2, t3;//分别代表 时间 时 分 秒
int td1, td2, td3;//分别代表 时间 时 分 秒
/*获取时间*/
time_t t;
struct tm * lt;
time(&t);//获取Unix时间戳。
lt = localtime(&t);//转为时间结构。
t1 = lt->tm_hour, t2 = lt->tm_min, t3 = lt->tm_sec;
td1 = lt->tm_year + 1900, td2 = lt->tm_mon + 1, td3 = lt->tm_mday;
/*获取的时间数值存入数组*/
ptim[0] = td1;//年
ptim[1] = td2;//月
ptim[2] = td3;//日
ptim[3] = t1;//时
ptim[4] = t2;//分
ptim[5] = t3;//秒
}
/*循环目录*/
int mean_l(struct student *head)
{
printf("【0】退出\n【1】新建or增加结点\n【2】插入指定结点\n【3】去除重复结点\n");
printf("【4】删除指定结点\n【5】查看现有结点\n\n");
char c;
printf(" ");
c = getchar();
printf("***\n");
int i = c - '0';
switch (i)
{
case 0: exit(0); break;
case 1: input_creact_lian(head); break;
case 2: add_l(head); break;
case 3: Duplicate_removal(head); break;
case 4: del_l(head); break;
case 5: output_l(head); break;
default:
printf("****** Err 输入错误。。。*******\n\n");
}
rewind(stdin);//fflush(stdin);在VS中无效
mean_l(head);
return 0;//虽然没啥用,但是没有它会警告 没有返回值
}
/*主函数*/
int main(void)
{
printf("\n************学生签到信息表*************\n\n");
struct student *head;//创建头结点
if ((head = (struct student *)malloc((sizeof(struct student)))) == NULL)
{
printf(" Sorry 分配内存失败。。。");
exit(0);
}
memset(head, 0, sizeof(struct student));//初始化头结点
head->front = head->back = head;//头结点自循环
mean_l(head);
system("pause");
}