知识点12:链表

链表

链表
头指针
结点
数据域
指针域

1,建立静态链表

#include <stdio.h>
struct Student
	{
    
    
		int num;
		float score;
		struct Student *next;//在结构体变量中定义一个本类型指针next,指针指向的是一个结构体变量 
	}; 
int main()
{
    
    
	struct Student a, b, c, *p; 
	a.num = 10101; a.score = 89.5; a.next = &b;
	b.num = 10103; b.score = 90;   b.next = &c;
	c.num = 10107; c.score = 85;   c.next = NULL;//每个结构体变量中的next指针都指向下一个结构体变量,直到最后一个,指向NULL 
	struct Student *head = &a;//定义一个头指针
	p = head;//p最开始为头指针,然后一个一个的指下去 
	do
	{
    
    
		printf("%ld\t%.1lf\n", p->num, p->score);//输出指针此时所指的结构体变量中的某个成员(仅通过指针的变化来输出其它) 
		p = p->next;//一个一个的指下去,为输出下一个结点做准备 
	}while(p != NULL);
	return 0;
}

在声明结点的数据结构时,通常结合typedef以简化代码,,也使代码更清晰。

struct 结构名
{
    
    
	数据类型1 变量1;
	数据类型2 变量2;
	struct 结构名 *next;
};
typedef struct 结构名 node;//简化结构体变量名(结点)
typedef node* link;//简化结构体指针名
struct Student
	{
    
    
		int num;
		float score;
		struct Student *next; 
	}; 
typedef struct Student node;
typedef node* link;
int main()
{
    
    
	node a, b, c; 
	a.num = 10101; a.score = 89.5; a.next = &b;
	b.num = 10103; b.score = 90;   b.next = &c;
	c.num = 10107; c.score = 85;   c.next=NULL;
	link head, p;
	head = &a;
	p = head;

2,建立动态链表

#include <stdio.h>
#include <stdlib.h>
#define LEN sizeof(struct Student)//规定每次开辟的空间大小(即结点大小)(sizeof是求字节数运算符)
 
struct Student
{
    
    
	long num;
	float score;
	struct Student *next;
};
typedef struct Student node;//结点 
typedef node* link;//结点的指针 
int n = 0;//n为结点个数 

/*思路:让p_new指向新开辟的结点,p_end指向链表中的最后一个结点,
再将p_new所指的结点连接在p_end所指的结点后面,用 p_end->next = p_new实现 */
link create(void)//定义指针类型函数(返回头指针)create  建立链表 
{
    
    
	link p_new, p_end, head = NULL;//先使head为NULL,这是链表为"空”时的情况(即链表中无结点),当建立第一个结点,就使head指向该结点 
	p_new = p_end = (link)malloc(LEN);//用malloc函数开辟第一个结点,并使p_new和p_end指向他(强制类型转换) 
	/*编译系统可以进行隐式的类型转换 因此可以:
	p_new = p_end = malloc(LEN);                         */ 
	scanf("%ld,%f", &p_new->num, &p_new->score);//输入数据给p_new所指的第一个结点  
	while (p_new->num != 0)//规定输入学号为0表示建立链表的过程完成 
	{
    
                    //若输入的学号不为0,则输入的是结点数据 
		n ++;//若输入的学号不为0,则结点数+1 ,n为结点个数 
		if (n == 1)
			head = p_new;//将head指向第一个结点 
		else 
			p_end->next = p_new;//若该结点不是第一个结点,就将该结点连接到上一个结点的表尾(next和p1均为指针变量) 
		p_end = p_new;//将p_new所指向的结点交给p_end来指向,即p_end为链表的最后一个结点 
		p_new = (link)malloc(LEN);//p1去指向另一个新开辟的结点 
		scanf("%ld,%f", &p_new->num, &p_new->score);//再向这个新开辟的结点中输入数据 
	}
	p_end->next = NULL;//建立链表结束后,使上一个结点中的next指针指向空NULL
	free(p_new); //释放掉没有用到的空间 
	return (head);//链表已建立完成,知道表头head就可以调动一整串链表,因此仅返回第一个结点的起始地址就好 
}

void print(link head)//定义一个指针类型的函数print 输出链表 
{
    
    
	link p;
	p = head;//p从head处开始,即指向第一个结点 
	if (head != NULL)//保证链表不为空 
	{
    
    
		do
		{
    
    
			printf("\nnum:%ld\nscore:%.1f\n", p->num, p->score);//输出p此时所指的结点中的信息 
			p = p->next;//p再指向下一个结点,再输出 
		}while (p != NULL);//直到链表的尾结点中的next指针指向NULL 
	}
}

int main()
{
    
    
	link pt;
	pt = create();//指针指向所创建的链表的表头 
	print(pt);
	return 0;
 } 

3,链表的相关操作

1,插入结点
//功能:输入某个学号(结点),则会在该结点后插入一个结点,再在该结点中存入学号、成绩,输出时所有成绩会按结点连接顺序输出 
struct Student* insert(long k, struct Student *head)//返回头指针 
{
    
    
	struct Student *p, *temp;
	if (head != NULL)
	{
    
    
		if (k == 0)//在第一个结点之前插入结点 
		{
    
    
			p = (struct Student*)malloc(LEN);//先开辟再连接 
			printf("请输入您想要插入的数据:\n"); 
			scanf("%ld,%f", &p->num, &p->score);
			p->next = head;
			head = p;//头指针发生改变 
		}
		else
		{
    
    
			p = head;
			while (p->num != k)
				p = p->next;//移到下一个结点 
			temp = p->next;//将原本要指向的下一个结点记为temp 
			p->next = (struct Student*)malloc(LEN);//在中间建立新的空间,存入结点数据
			p = p->next;//移到新开辟的结点 
			printf("请输入您想要插入的数据:\n"); 
			scanf("%ld,%f", &p->num, &p->score);//让结点里的指针指向这个新创建的空间(即新的结点) 
			p->next = temp; //这个新结点再指向temp			
		} 
	}
	return head;//返回头指针
}
2,删除结点
//删除节点函数
//功能:输入一个学号(节点),则链表中会删去结点,即输出成绩时不会输出该同学的成绩 
struct Student* del(long k, struct Student *head)
{
    
    
	struct Student *p = head, *temp;
	if (head->num == k)//若删除的是第一个结点 
	{
    
    
		head = head->next;//则要改变head
		free(p);//释放掉被删除的结点的空间 
		return(head);//返回head,即新表头的地址,主函数中输出时,从新表头开始输出
		             //同时也终止函数的运行 
	}
	if (head != NULL)
	{
    
    
		while ((p->next)->num != k)
			p = p->next;
		temp = p->next;
		p->next = (p->next)->next;//遇到需要删除的结点时,前一个结点里的指针指的是下下个结点的地址,即跳过需要删除的结点 
		free(temp);//释放掉被删除的结点的空间 
	}
	return(head);
}

猜你喜欢

转载自blog.csdn.net/Shao_yihao/article/details/113394954