数据结构:带头结点的单链表和双链表相关操作

单链表(带头结点)

头结点保存链表长度和链表的第一个节点的地址,其余增删改查操作相比于不带头结点的单链表更简单。我这里用简单的学生信息系统体现增删改查操作。

  1. linklist.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "linklist.h"
    
    NODE *create_node(){
    	NODE *p = (NODE*)malloc(sizeof(NODE));
    	if(p == NULL){
    		puts("Error:内存分配失败");
    		exit(-1);
    	}
    	p->id = 0;
    	p->next = NULL;
    	p->score = 0;
    	return p;
    }
    /*尾插录入*/
    void create_linklist(F_NODE *const first){
    	NODE *p = create_node();
    	while(1){
    		printf("请输入学号:");
    		scanf("%d",&p->id);
    		while(getchar()!='\n');
    		if(linklist_search1(first,p->id) == NULL && p->id > 0){
    			break;
    		}
    		else{
    			puts("=>该学生已存在或输入有误,请重新添加");
    		}
    	}
    	printf("请输入姓名:");
    	fgets(p->name,32,stdin);
    	char *find = strchr(p->name,'\n');
    	if(find) *find = '\0';
    	printf("请输入成绩:");
    	scanf("%lf",&p->score);
    	while(getchar()!='\n');
    	
    	if(first->next == NULL){
    		first->next = p;
    	}
    	else{
    		/*尾插*/
    		NODE *find = first->next;
    		while(find->next != NULL) find = find->next;
    		find->next = p;
    	}
    	first->len++;
    }
    /*根据学号查找学生*/
    NODE* linklist_search1(const F_NODE * first,const int stu_id){
    	if(first->next == NULL){
    		return NULL;
    	}
    	NODE *find = first->next;
    	while(find != NULL){
    		if(find->id == stu_id){
    			return find;
    		}
    		find = find->next;
    	}
    	/*没有则查找失败*/
    	return NULL;
    }
    /*根据姓名查找学生*/
    NODE *linklist_search2(const F_NODE * first,const char *name){
    	if(first->next == NULL){
    		puts("=>无任何学生信息");
    		return NULL;
    	}
    	NODE *find = first->next;
    	while(find != NULL){
    		if(!strcmp(find->name,name)){
    			return find;
    		}
    		find = find->next;
    	}
    	/*没有则查找失败*/
    	return NULL;
    }
    /*根据学号删除学生*/
    void linklist_delete1(F_NODE *const first,const int stu_id){
    	NODE *del = linklist_search1(first,stu_id); 
    	if(del == NULL){
    		puts("=>没有该学生");
    		return;
    	}
    	/*头删*/
    	if(del == first->next){
    		first->next = del->next;
    	}
    	else{
    		/*找到待删除节点的前一个节点*/
    		NODE *find = first->next;
    		while(find->next != del) find = find->next;
    		find->next = del->next;
    	}
    	free(del);
    	first->len--;		
    }
    /*根据姓名删除学生*/
    void linklist_delete2(F_NODE *const first,const char *name){
    	NODE *del = linklist_search2(first,name);
    	if(del == NULL){
    		puts("=>没有该学生");
    		return;
    	}
    	/*头删*/
    	if(del == first->next){
    		first->next = del->next;
    	}
    	else{
    		/*找到待删除节点的前一个节点*/
    		NODE *find = first->next;
    		while(find->next != del) find = find->next;
    		find->next = del->next;
    	}
    	free(del);
    	first->len--;		
    }
    /*修改学生信息*/
    void linklist_change(NODE *const search,const int opt){
    	char *find = NULL;
    	switch(opt){
    		case 1:
    			printf("输入新的学号:");
    			scanf("%d",&search->id);
    			while(getchar()!='\n');
    			break;
    		case 2:
    			printf("输入新的名字:");
    			fgets(search->name,32,stdin);
    			find = strchr(search->name,'\n');
    			if(find) *find = '\0';
    			break;
    		case 3:
    			printf("输入新的成绩:");
    			scanf("%lf",&search->score);
    			while(getchar()!='\n');
    			break;
    	}
    }
    /*显示所有学生*/
    void show_list(const F_NODE *const first){
    	if(first->next == NULL){
    		puts("=>无任何学生信息");
    		return;
    	}
    	else{
    		NODE *p = first->next;
    		puts("学号\t姓名\t成绩");
    		while(p != NULL){
    			printf("%.3d\t%s\t%.1lf\n",p->id,p->name,p->score);
    			p = p->next;
    		}
    	}
    	
    }
    
  2. linklist_sort.c

    #include <stdio.h>
    #include "linklist.h"
    NODE *find_max(const F_NODE *const first,const int opt){
    	NODE *p = first->next;
    	NODE *pmax = p;
    	int max_id = p->id;
    	double max_score = p->score;
    	switch(opt){
    		case 1:
    			while(p != NULL){
    				if(max_id < p->id){
    					max_id = p->id;
    					pmax = p;
    				}
    				p = p->next; 
    			}
    			break;
    		case 2:
    		case 3:
    			while(p != NULL){
    				if(max_score < p->score){
    					max_score = p->score;
    					pmax = p;
    				}
    				p = p->next; 
    			}
    			break;
    	}
    	return pmax;
    }
    
    void move_max(F_NODE *const first,NODE *const pmax){
    	if(pmax == first->next){
    		first->next = pmax->next;
    	}
    	else{
    		NODE *find = first->next;
    		while(find->next != pmax) find = find->next;
    		find->next = pmax->next;
    	}
    	pmax->next = NULL;
    }
    /*按学号升序或降序*/
    void linklist_sort(F_NODE *const first,const int opt){
    	NODE *pmax = NULL;
    	NODE *head = NULL;
    	NODE *tail = NULL;
    	while(first->next != NULL){
    		switch(opt){
    			case 1:
    				/*从原链表中找出最大节点地址*/
    				pmax = find_max(first,opt);
    				/*从链表中移出最大节点*/
    				move_max(first,pmax);
    				/*头插放到无头结点新链表*/
    				pmax->next = head;
    				head = pmax;
    				break;
    			case 2:
    				/*从原链表中找出最大节点地址*/
    				pmax = find_max(first,opt);
    				/*从链表中移出最大节点*/
    				move_max(first,pmax);
    				/*头插放到无头结点新链表*/
    				pmax->next = head;
    				head = pmax;
    				break;
    			case 3:
    				/*从原链表中找出最大节点地址*/
    				pmax = find_max(first,opt);
    				/*从链表中移出最大节点*/
    				move_max(first,pmax);
    				/*尾插放入无头结点链表*/
    				if(head == NULL){
    					head = pmax;
    					tail = head;
    				}
    				else{
    					tail->next = pmax;
    					tail = pmax;
    				}
    				break;
    		}
    	}
    	first->next = head;
    }
    
  3. fileIO.c

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include "linklist.h"
    
    void fileWrite(F_NODE *first){
    	FILE *fp = fopen("./stu_info.txt","w");
    	if(fp == NULL){
    		perror("write");
    		fclose(fp);
    		exit(-1);
    	}
    	NODE *p = first->next;
    	while(p != NULL){
    			fprintf(fp,"%d\t%s\t%.1lf\n",p->id,p->name,p->score);
    			p = p->next;
    	}
    	fclose(fp);
    }
    int fileRead(F_NODE *first){
    	FILE *fp = fopen("./stu_info.txt","r");
    	if(fp == NULL){
    		perror("write");
    		exit(-1);
    	}
    	int count = 0;
    	NODE temp;
    	temp.next = NULL;
    	NODE *tail = NULL;
    	while(EOF != fscanf(fp,"%d%s%lf",&temp.id,temp.name,&temp.score)){
    		NODE *p = create_node();
    		*p = temp;
    		/*判断链表是否为空*/
    		if(first->next == NULL){
    			first->next = p;
    		}
    		else{
    			tail->next = p; 
    		}
    		/*读取个数*/
    		count++;
    		/*尾指针指向新创建的节点*/
    		tail = p;	
    	}
    	return count;
    }
    void progressBar(int n){
    	/*进度条状态数组*/
    	char buff[40];
    	/*字符数组清零*/
    	memset(buff,'\0',40);
    	/*动态标签*/
    	char label[] = "\\/\\/";
    	for(int i = 0;i < 40;i++){
    		printf("[%-39s][%c][%.1f%%]\r",buff,label[i%4],(i+1)*2.5);
    		/*刷新缓冲区,先将缓冲区已有的内容打印*/
    		fflush(stdout);
    		buff[i] = '#';
    		/*等待0.1s(100000us)刷新进度条*/
    		usleep(n*500+2000);
    	}
    	putchar('\n');
    }
    
  4. main.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "menuFrame.h"
    #include "linklist.h"
    #include "linklist_sort.h"
    #include "fileIO.h"
    
    int main(){
    	F_NODE *first = (F_NODE*)malloc(sizeof(F_NODE));
    	if(first == NULL){
    		puts("Error:内存申请失败");
    		exit(-1);
    	}
    	first->next = NULL;
    	int count = fileRead(first);
    	first->len = count;
    	puts("=>读取中...");
    	progressBar(count);
    	show_list(first);
    	while(1){
    		mainFrame();
    		int opt,flag = 1;
    		int stu_id;
    		char name[32],*find;
    		NODE *search = NULL;
    		printf("输入操作选项:");
    		scanf("%d",&opt);
    		while(getchar()!='\n');
    		switch(opt){
    			case 1:
    				create_linklist(first);
    				break;
    			case 2:
    				while(flag){
    					deleteFrame();
    					printf("输入选项:");
    					scanf("%d",&opt);
    					while(getchar()!='\n');
    					switch(opt){
    						case 1:
    flag1:
    							printf("请输入学号:");
    							scanf("%d",&stu_id);
    							while(getchar()!='\n');
    							search = linklist_search1(first,stu_id);
    							if(search == NULL){
    								puts("==>学号不存在");
    								goto flag1;
    							}
    							else{
    								linklist_delete1(first,stu_id);
    								puts("==>删除成功");
    							}
    							break;
    						case 2:
    flag2:
    							printf("请输入姓名:");
    							fgets(name,32,stdin);
    							find = strchr(name,'\n');
    							if(find) *find = '\0';
    							search = linklist_search2(first,name);
    							if(search == NULL){
    								puts("==>姓名不存在");
    								goto flag2;
    							}
    							else{
    								linklist_delete2(first,name);
    								puts("==>删除成功");
    							}
    							break;
    						case 0:
    							flag = 0;
    							break;
    						default:
    							puts("==>指令错误");
    							break;
    					}
    				}
    				break;
    			case 3:
    				while(flag){
    					printf("请输入学号:");
    					scanf("%d",&stu_id);
    					while(getchar()!='\n');
    					search = linklist_search1(first,stu_id);
    					if(search == NULL){
    						puts("=>没有该学生");
    						continue;
    					}
    					printf("该学生信息:[学号:%.3d|姓名:%s|成绩:%.1lf]\n",stu_id,search->name,search->score);
    					while(flag){
    						changeFrame();
    						printf("请输入选项:");
    						scanf("%d",&opt);
    						while(getchar()!='\n');
    						switch(opt){
    							case 1:
    								linklist_change(search,1);
    								break;
    							case 2:
    								linklist_change(search,2);
    								break;
    							case 3:
    								linklist_change(search,3);
    								break;
    							case 0:
    								flag = 0;
    								break;
    							default:
    								puts("==>指令有误");
    								break;
    						}
    					}
    					break;
    				}
    				break;
    			case 4:
    				while(flag){
    					searchFrame();
    					printf("输入选项:");
    					scanf("%d",&opt);
    					while(getchar()!='\n');
    					switch(opt){
    						case 1:
    flag3:
    							printf("请输入学号:");
    							scanf("%d",&stu_id);
    							while(getchar()!='\n');
    							search = linklist_search1(first,stu_id);
    							if(search == NULL){
    								puts("==>学号不存在");
    								goto flag3;
    							}
    							else{
    								printf("该学生信息:[学号:%.3d|姓名:%s|成绩:%.1lf]\n",stu_id,search->name,search->score);
    							}
    							break;
    						case 2:
    flag4:
    							printf("请输入姓名:");
    							fgets(name,32,stdin);
    							find = strchr(name,'\n');
    							if(find) *find = '\0';
    							search = linklist_search2(first,name);
    							if(search == NULL){
    								puts("==>姓名不存在");
    								goto flag4;
    							}
    							else{
    								printf("该学生信息:[学号:%.3d|姓名:%s|成绩:%.1lf]\n",search->id,search->name,search->score);
    							}
    							break;
    						case 0:
    							flag = 0;
    							break;
    						default:
    							puts("==>指令错误");
    							break;
    					}
    				}
    				break;
    			case 5:
    				while(flag){
    					showFrame();
    					printf("输入选项:");
    					scanf("%d",&opt);
    					while(getchar()!='\n');
    					switch(opt){
    						case 1:
    							linklist_sort(first,opt);
    							show_list(first);
    							break;
    						case 2:
    							linklist_sort(first,opt);
    							show_list(first);
    							break;
    						case 3:
    							linklist_sort(first,opt);
    							show_list(first);
    							break;
    						case 0:
    							flag = 0;
    							break;
    						default:
    							puts("==>指令有误");
    							break;
    					}
    				}
    				break;
    			case 0:
    				puts("=>已退出,正在保存...");
    				progressBar(first->len);
    				fileWrite(first);
    				return 0;
    		}
    	}
    	return 0;
    }
    

双向链表(带头结点)

在这里插入图片描述

  1. 头插法创建

    /*开辟内存*/
    NODE *create_Node(){
    	NODE *p = (NODE*)malloc(sizeof(NODE));
    	if(!p){
    		puts("Error:分配内存失败");
    		return NULL;
    		exit(-1);
    	}
    	p->data = 0;
    	p->prev = NULL;
    	p->next = NULL;
    	return p;
    }
    /*带头结点双链表头插*/
    void linklist_create(NODE *head,int data){
    	NODE *p = create_Node();
    	p->data = data;
    	/*先连*/
    	p->next = head->next;
    	p->prev = head;
    	/*后断*/
    	if(head->next == NULL){
    		head->next = p;
    	}
    	else{
    		head->next->prev = p;
    		head->next = p;
    	}
    	head->data++;
    }
    
  2. 查找指定数据

    NODE *linklist_search(NODE *head,int data){
    	NODE *p = head->next;
    	while(p){
    		if(data == p->data){
    			return p;
    		}
    		p = p->next;
    	}
    	return NULL;
    }
    
  3. 删除指定数据节点

    void linklist_delete(NODE *head){
    	int data;
    	printf("输入删除的数据:");
    	scanf("%d",&data);
    	while(getchar()!='\n');
    	NODE *find = linklist_search(head,data);	
    	if(find){
    		find->prev->next = find->next;
    		if(find->next){
    			find->next->prev = find->prev;
    		}
    		find->next = NULL;
    		find->prev = NULL;
    		free(find);
    		head->data--;
    	}
    	else{
    		puts("=>删除失败");
    	}
    }
    
  4. 数据排序(升序)

    NODE *find_min(NODE *head){
    	NODE *p = head->next;
    	NODE *pmin = p;
    	for(int i = 0;i < head->data;i++){
    		if(p->data < pmin->data){
    			pmin = p;
    		}
    		p = p->next;
    	}
    	head->data--;
    	return pmin;
    }
    void move_min(NODE *head,NODE *pmin){
    	pmin->prev->next = pmin->next;
    	if(pmin->next){
    		pmin->next->prev = pmin->prev;
    	}
    	pmin->prev = NULL;
    	pmin->next = NULL;
    }
    void insert_min(NODE *head,NODE *pmin){
    	NODE *find = head;
    	while(find->next != NULL) find = find->next;
    	find->next = pmin;
    	pmin->prev = find;
    }
    void linklist_sort(NODE *head){
    	if(!head->next){
    		return;
    	}
    	int len = 0;
    	while(head->data){
    		NODE *pmin = find_min(head);
    		move_min(head,pmin);
    		/*尾插到原链表最后*/
    		insert_min(head,pmin);
    		len++;
    	}
    	head->data = len;
    }
    
  5. 释放链表

    void linklist_free(NODE **head){
    	if((*head)->next){
    		linklist_free(&(*head)->next);
    		free((*head)->next);
    	}
    	*head = NULL;
    }
    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
带头结点单链表是指在链表的头部增加一个额外的结点,该结点不存储具体的数据,而是用来作为链表的头指针的前驱。这样做的好处是在进行插入和删除操作时不需要特殊处理链表为空的情况,因为头结点始终存在。 双链表是指每个结点都有两个指针,一个指向直接后继结点,一个指向直接前驱结点。这样可以方便地从任意一个结点开始访问它的前驱结点和后继结点。与单链表相比,双链表操作更加灵活,但是相应地需要多维护一个指针域。 所以,带头结点单链表双链表的区别在于双链表每个结点都有指向前驱结点的指针,而带头结点单链表只有指向后继结点的指针。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [C语言使用非循环双向链表实现队列](https://download.csdn.net/download/weixin_38704565/13757045)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [链表(一) -- 单链表与双向链表](https://blog.csdn.net/JeremyIverson/article/details/104282271)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [数据结构单链表双链表](https://blog.csdn.net/guyuanxiang1995/article/details/76927042)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值