学习C(十九)

双向链表(案例)

/*
学生信息的添加,查找,删除
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct Data{
	char name[20];
	int age;
	int score;
}data_t;

typedef struct Stu{
	data_t data;
	struct Stu* next;//指向下一个的指针域
	struct Stu* prev;//指向上一个的指针域
}stu_t;

stu_t* initStu(){
	stu_t* head = malloc(sizeof(stu_t));
	memset(head,0,sizeof(stu_t));
	head->next = NULL;
	head->prev = NULL;
}

/*
	注意:一张链表,他到底是什么形式的,完全取决于添加函数如何写,而不是取决于链表的元素有哪些指针域。
	因为即使有next和prev指针,添加函数只链接next,不链接prev,那么这张链表就是单向链表。只有next和prev都链接了,才是双向链表
*/

void printStu(stu_t* head){
	stu_t* p = head->next;
	while(p!=NULL){
		printf("*************\n");
		printf("姓名:%s\n",p->data.name);
		printf("年龄:%d\n",p->data.age);
		printf("分数:%d\n",p->data.score);//注意:如果这里把%d改成%s会出现段错误
		p = p->next;
	}
	printf("*************\n");
}

stu_t* findStu(stu_t* head){
	char name[20] = {0};
	stu_t* p = head->next;
	printf("请输入学生姓名:");
	scanf("%s",&name);
    while(getchar()!=10);
	while(p!=NULL){
		if(strcmp(p->data.name,name)==0){
			return p;
		}
		p = p->next;
	}
	return NULL;
}

/*
	双向链表的删除比单向表简单非常多
*/
void removeStu(stu_t* head){
	stu_t* tar = findStu(head);
	//tar就是目标了
	if(tar==NULL){return;}
	/*
		tar->prev不太可能导致段错误,因为只有tar是head的时候,tar->prev才会是空,但是find不可能返回head,
		但是tar->next很有可能为空,因为find一旦返回尾节点,tar-next就是空的
	*/
	tar->prev->next = tar->next;
	if(tar->next != NULL){
		tar->next->prev = tar->prev;
	}
	free(tar);
}

void freeStu(stu_t* head){
	stu_t* p = head;
	while(p->next!=NULL){
		p = p->next;
		free(p->prev);
	}
	free(p);
}

void insertStu(stu_t* head){
	data_t st = {0};
    char name[20] = {0};
	printf("请输入姓名:");
    scanf("%s",name);
    while(getchar()!=10);
	static int age = 20;
    static int score = 80;
    strcpy(st.name,name);
	st.age = age;
	st.score = score;
	age++;
	score++;
	stu_t* newNode = calloc(1,sizeof(stu_t));
	newNode->data = st;
	//头插法:
	/*newNode->next = head->next;
	if(head->next!=NULL){
		head->next->prev = newNode;
	}
	newNode->prev = head;
	head->next = newNode;*/
	//尾插法
	stu_t* p = head;
	while(p->next != NULL){
		p = p->next;
	}
	p->next = newNode;
	newNode->next = NULL;
	newNode->prev = p;
}

int main(){
	stu_t* head = malloc(sizeof(stu_t));
	memset(head,0,sizeof(stu_t));

	insertStu(head);//添加学生信息
	insertStu(head);
	insertStu(head);
	printStu(head);
    printf("\n");
	removeStu(head);//删除学生
	printStu(head);
	freeStu(head);
	return 0;
}

双向循环链表(案例)

/*
学生信息的添加,查找,删除
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct Data{
	char name[20];
	int age;
	int score;
}data_t;

typedef struct Stu{
	data_t data;
	struct Stu* next;//指向下一个的指针域
	struct Stu* prev;//指向上一个的指针域
}stu_t;

//双向循环链表的头结点
stu_t* initStu(){
	stu_t* head = malloc(sizeof(stu_t));
	memset(head,0,sizeof(stu_t));
	head->next = head;
	head->prev = head;
}

//打印链表数据
void printStu(stu_t* head){
	stu_t* p = head->next;
	while(p != head){
		printf("*************\n");
		printf("姓名:%s\n",p->data.name);
		printf("年龄:%d\n",p->data.age);
		printf("分数:%d\n",p->data.score);
		p = p->next;
	}
	printf("*************\n");
}

//查找
stu_t* findStu(stu_t* head){
	char name[20] = {0};
	stu_t* p = head->next;
	printf("请输入学生姓名:");
	scanf("%s",name);
    while(getchar()!=10);
	while(p!=head){
		if(strcmp(p->data.name,name)==0){
			return p;
		}
		p = p->next;
	}
	return head;
}

//双向循环链表节点的删除
void removeStu(stu_t* head){
	stu_t* tar = findStu(head);
	tar->prev->next = tar->next;
	tar->next->prev = tar->prev;
	free(tar);
}
//双向循环链表的释放
void freeStu(stu_t* head){
	stu_t* p = head;
	while(p->next!=head){
		p = p->next;
		free(p->prev);
	}
	free(p);
}

//添加学生信息
void insertStu(stu_t* head){
	data_t data = {0};
    char name[20] = {0};
	int age = 0,score = 0;
    printf("请输入学生姓名:");
    scanf("%s",name);
    while(getchar()!=10);
    printf("请输入学生年龄:");
    scanf("%d",&age);
    while(getchar()!=10);
    printf("请输入学生成绩:");
    scanf("%d",&score);
    while(getchar()!=10);
    strcpy(data.name,name);
	data.age = age;
	data.score = score;
	stu_t* newNode = calloc(1,sizeof(stu_t));
	//寻找尾节点
	newNode->data = data;
	stu_t* p = head->prev;
	p->next = newNode;
	newNode->next = head;
	head->prev = newNode;
	newNode->prev = p;
}

//比较学生成绩
int compare_by_score(stu_t* a,stu_t* b){
	return a->data.score - b->data.score;
}

//双向循环链表的快速排序(按照成绩排序)
void lqsort(stu_t* head,stu_t* tail,int (*comp)(stu_t*,stu_t*)){
	//降序:左边找比key小的,右边找比key大的
	stu_t* left = head;
	stu_t* right = tail;
	if(left==right || right->next == left){return;}
	stu_t* l = left;
	stu_t* r = right;
	stu_t* key = left;
	data_t temp = {0};
	while(l!=r){
		while(l!=r){
			//key中的某一个值 - r中的某一个值 < 0
			if(comp(key,r)<0){
				break;
			}else{
				r = r->prev;
			}
		}
		while(l!=r){
			if(comp(key,l)>0){
				break;
			}else{
				l = l->next;
			}
		}
		temp = l->data;
		l->data = r->data;
		r->data = temp;
	}
	temp = l->data;
	l->data = left->data;
	left->data = temp;
	lqsort(head,l->prev,comp);
	lqsort(l->next,tail,comp);
}

int main(){
	stu_t* head = initStu();
	int i = 0;
	for(i=0;i<3;i++){
		insertStu(head);
	}
	printf("初始化完成\n");
	lqsort(head->next,head->prev,compare_by_score);
    printStu(head);
    printf("\n");
    removeStu(head);
    printStu(head);
    freeStu(head);
	return 0;
}

双向链表完成注册登录功能

/*
	使用双向链表:完成注册登录功能。
			要求注册时查重
			登录后可修改密码可注销账号
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct Data{
	char name[20];
	char pswd[20];
}data_t;

typedef struct Stu{
	data_t data;
	struct Stu* next;//指向下一个的指针域
	struct Stu* prev;//指向上一个的指针域
}stu_t;

//头节点
stu_t* initStu(){
	stu_t* head = calloc(1,sizeof(stu_t));
	head->next = NULL;
	head->prev = NULL;
	return head;
}

//打印双向链表数据
void printStu(stu_t* head){
	stu_t* p = head->next;
	while(p!=NULL){
		printf("*************\n");
		printf("账号:%s\n",p->data.name);
		printf("密码:%s\n",p->data.pswd);
		p = p->next;
	}
	printf("*************\n");
}

/*
函数名:findStu
函数参数:stu_t* head,char* name-要查找的名字
函数返回值:stu_t*
函数功能:查找和链表数据中名字,相同返回相同名字节点的地址,不同返回NULL
*/
stu_t* findStu(stu_t* head,char* name){
	stu_t* p = head->next;
	while(p!=NULL){
		if(strcmp(p->data.name,name)==0){
			return p;
		}
		p = p->next;
	}
	return NULL;
}

//注册及查重
void regist(stu_t* head){
	char name[20] = {0};
	char pswd[20] = {0};
	printf("请输入账号:");
	scanf("%s",name);
    while(getchar()!=10);
	stu_t* res = findStu(head,name);
	if(res != NULL){
		printf("账号以存在\n");
		return ;
	}
	printf("请输入密码:");
	scanf("%s",pswd);
	stu_t* newSt = calloc(1,sizeof(stu_t));
	strcpy(newSt->data.name,name);
	strcpy(newSt->data.pswd,pswd);
	stu_t* p = head;
	while(p->next != NULL){
		p = p->next;
	}
	p->next = newSt;
	newSt->next = NULL;
	newSt->prev = p;
}

//登录
stu_t* login(stu_t* head){
	char name[20] = {0};
	char pswd[20] = {0};
	while(1){
		printf("请输入账号:");
		scanf("%s",name);
        while(getchar()!=10);
		printf("请输入密码:");
		scanf("%s",pswd);
        while(getchar()!=10);
		stu_t* res = findStu(head,name);
		if(res==NULL||strcmp(pswd,res->data.pswd)!=0){
			printf("账号或密码错误\n");
			printf("输入q+回车退出登录,输入其他则继续:");
			if(getchar()=='q'){
                while(getchar()!='\n');
                break;
            }
		}else{
		    printf("登录成功\n");
            return res;
		}	
	}
	return 0;
}

//修改密码
void updatePswd(stu_t* self){//注意此处传进来的是要修改的链表节点的地址
	char pswd[20] = {0};
	printf("请输入新的密码:");
	scanf("%s",pswd);
    while(getchar()!=10);
	strcpy(self->data.pswd,pswd);
}

//注销
void removeStu(stu_t* self){
	self->prev->next = self->next;
	if(self->next != NULL){
		self->next->prev = self->prev;
	}
}

//用户界面
void userInterface(stu_t* head,stu_t* self){
	int res = 0;
	int ch = 0;
	while(1){
		printf("1:查看个人信息\n");
		printf("2:修改密码\n");
		printf("3:注销\n");
		printf("0:退出登录\n");
		scanf("%d",&ch);
		while(getchar()!='\n');
		switch(ch){
			case 1:
				printf("账号:%s\n",self->data.name);
				printf("密码:%s\n",self->data.pswd);
				break;
			case 2:
				updatePswd(self);
				return;
			case 3:
				removeStu(self);
				return;
			case 0:
				return ;
			default:
				break;
		}
	}
}


int main(){
	int ch = 0;
	stu_t* head = initStu();
	stu_t* res = 0;
	while(1){
		printf("1:注册\n");
		printf("2:登录\n");
		printf("0:退出\n");
		/*while(1){
			ch = getch()-'0';
			if(ch>=0 || ch<=2){break;}
		}*/
		scanf("%d",&ch);
		while(getchar()!='\n');
		switch(ch){
			case 1:
				regist(head);
				break;
			case 2:
				res = login(head);
				if(res!=NULL){
					userInterface(head,res);
				}
				break;
			case 0:
				break;
			default:
				break;
		}
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值