【自学】链表

主程序

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//结构体定义 
struct stud_node {
	int num;
	char name[20];
	int score;
	struct stud_node * next;
}; 
//函数声明
struct stud_node * Create_Stu_Doc (void);
struct stud_node * InsertDoc (struct stud_node * head, struct stud_node * stud,int target);
struct stud_node * DeleteDoc (struct stud_node * head, int num);
void Print_Stu_Doc (struct stud_node * head);

int main (void){
	struct stud_node *head, *p;
	int choice, num, score,target;
	char name[20];
	int size = sizeof(struct stud_node);
	
	do{
		printf("1: Create 2: Insert 3: Delete 4: Print 0: Exit\n");
		scanf("%d",&choice);
		switch(choice){			
			case 1:
				head = Create_Stu_Doc ();
				break;
			case 2:
				if(head == NULL) {
					printf("No Data Yet! Please Create A Node First\n");
					break;
				}
				target = -1;
				printf("Insert A Student's Data After Num ");
				scanf("%d",&target);
				putchar('\n');				
				printf("Input num, name and score: \n");
				scanf("%d%s%d",&num,name,&score);
				p = (struct stud_node*)malloc(size);
				p->num = num;
				strcpy(p->name,name);
				p->score = score;
				head = InsertDoc(head,p,target);
				break;
			case 3:
				printf("Input num: \n");
				scanf("%d",&num);
				head = DeleteDoc (head,num);
				break;
			case 4:
				Print_Stu_Doc (head);
				break;
			case 0:
				break;
		}
	}while (choice != 0);
	
	return 0;
}

链表的建立

函数的输入为,返回值为strcut stud_node*

//按照输入顺序建立单向链表
struct stud_node * Create_Stu_Doc (void){
	int num,score;
	char name[20];
	int size = sizeof (struct stud_node) ;
	struct stud_node *head, *tail, *p;
	head = tail = p =NULL;
	printf("Input num, name and score: \n");
	scanf("%d%s%d",&num,name,&score);
	while (num != 0){
		p = (struct stud_node*)malloc(size);
		p->num = num;
		strcpy(p->name,name);
		p->score = score;
		p->next = NULL;
		if(head == NULL) 
			head = p;
		else 
			tail->next = p;
		tail = p;
		scanf("%d%s%d",&num,name,&score);
	}
	return head;
}

由于需要新建一个链表,所以不需要输入。在定义的时候按照结构体里面的内容,定义int num,score;以及char name[20];等内容。通过sizeof来测量出链表的空间,以便动态内存申请。对于一个链表,需要有头(head)和尾(tail)以及指向结点的指针(p)。为了安全,让这些strcut stud_node *型的指针全部为NULL。#读入相应的数据。当编号不为0的时候,申请内存空间,然后让对应赋值(name需要用字符串处理函数进行处理)。对于指针head来说,如果是NULL的话,让他等于第一次申请时p的地址;否则由于已经有了链表而且tail指向上一个结点,通过tail->next = p;将上一个节点和新建的节点连接起来。再次读入数据判断是否结束,然后返回这个链表的头指针。
注意:链表的头一旦确定,不在改动,但是链表的尾会随着节点的变动而变动,指针p的作用是用来指向动态内存分配后的那个内存空间。
在这里插入图片描述
如果要反向建立结点,就使用p->next = head; head = p;最后的结果就是头变成尾,不需要tail了(因为head其实承担了tail的作用)

链表的遍历

void Print_Stu_Doc (struct stud_node * head){
	struct stud_node * ptr = head;
	if(ptr == NULL) {
		printf("\nNo Records!\n");
		return ;
	}
	printf("\nThe Students' Records Are: \n");
	printf("Num \t Name \t Score \n");
	while( ptr != NULL ){
		printf("%d \t %s \t %d \n",ptr->num,ptr->name,ptr->score);
		ptr = ptr->next;
	}
	return ;
}

链表在遍历的时候,需要传入头的指针,没有返回值。原理就是头指针的值给ptr,如果ptr为NULL,那么就说明没有数据,直接return ;即可。如果不是NULL,那么就需要通过while循环遍历链表,每次遍历包括打印内容和让ptr指向下个结点,最终指向NULL的时候说明链表结束。
在这里插入图片描述

添加结点

struct stud_node * InsertDoc (struct stud_node * head, struct stud_node * stud,int target){
	struct stud_node *ptr = head;
	while ( target != ptr->num && ptr != NULL){
		ptr = ptr->next;
	}
	if(ptr == NULL){
		printf("Not Found\n");
		return head;
	}
	stud->next = ptr->next;
	ptr->next = stud;
	return head;
}

首先传入的参数是两个指针head和stud,以及整型target。在主函数可以知道调用这个函数之前,对head是否为NULL做了一次判断,如果是NULL的话就要先创建一个链表,再执行插入的语句。传入的head是原来链表的头,为了遍历用。stud是新创建结点的地址,target代表插入到这个编号的后面。对链表进行遍历,如果找到target,ptr指向那个编号在的结点;如果没找到,输出Not Found。找到了以后,先将新增结点和后面的结点连接,在断开原来的连接,最终实现插入一个结点的目的。
在这里插入图片描述

删除结点

struct stud_node * DeleteDoc (struct stud_node * head, int num){
	struct stud_node *ptr1, *ptr2;
	while(head !=NULL && head->num==num){
		ptr2=head;
		head=head->next;
		free(ptr2);
		ptr2=NULL;
	}
	if (head == NULL){
		printf("No Data\n");
		return NULL;
	}
	ptr1=head;
	ptr2=ptr1->next;
	while (ptr2 != NULL){
		if(ptr2->num==num){
			ptr1->next=ptr2->next;
			free(ptr2);
			ptr2=NULL;
		}else{
			ptr1 = ptr2;
			ptr2 = ptr1->next;
		}
	}
	return head;
}

函数传入了头指针和删除结点的num。如果要删除一个头结点的话,只需要将头向后移动一个结点,然后free之前的头即可。如果要删除一个非头结点,那么需要让ptr1指向ptr2所指的结点的前一个结点。当ptr2指向要删除的结点时,让ptr1->next(注意不是ptr1)指向删除结点的下个结点即ptr2->next,然后free(ptr2)即可。
在这里插入图片描述

总结

以上便是对链表的基本操作,各个函数的功能可以随着具体的问题需求改变,传入的参数和返回的参数都可以做出改变。比如插入和删除的时候可以将函数定义成void类型。但是定义成struct stud_node * 类型可以后期修改时返回插入结点的指针,进行一些操作。
程序参考何钦铭与颜晖主编的C语言程序设计第三版11.3,并进行了一定的修改。如有不对,不合理之处,还望指出。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值