第十四次课:链表

0、为何学习链表

学习数据结构做准备。学了数据结构会发现数据可以组合成各种形状,线性表,堆栈,队列,串,树状,图等。

1、链表和数组的区别

数组建立之后不可修改(增删),链表可以。比如建立数组之后,增加一个元素,实现起来就是插入一个元素,然后该元素后面的所有元素都需要往后撤一个位置,数组实现起来很麻烦。再比如删掉一个元素,那么后面的元素都需要往前前进一个位置,实现起来也很麻烦。而链表实现增删操作则很容易,只是一句赋值语句而已。

数组是静态的,链表是动态的。虽然C99允许数组个数是一个变量,后期输入,但是一旦输入了也不好再修改,但是链表不同,链表非常方便完成增删操作,所以链表可以随时根据我们的需要增加或者释放一个元素。

2、链表的结构

链表有头指针和结点组成,头指针是一个存储单元,这个存储单元存放一个地址,该地址指向一个元素(结点),每个结点包括两部分,一部分是实际数据,另一部分是下一个结点的地址。链表类似火车,头指针像一个火车头,结点类似火车厢,火车厢通过每节车厢后的挂绳链接再一起,但是火车厢总有结束的时候,最后一节火车厢不链接任何东西,称为火车尾,类似的,链表中最后一个结点称为表尾,它也是一个结点,结点地址部分放一个NULL(空地址)。

3、静态链表的建立

链表有一个头指针和多个结点组成,头指针使用指针实现即可,而结点又包括两部分内容,且两部分内容的数据类型不一样,在我们所学习的数据类型中,只有结构可以胜任了,例如可以如下定义结点的结构类型:

struct Student 
{
    int num;
    float score;
    struct Student *next;
};

其中num和score是实际数据,next是下一个结点的地址,每个结点都是一个结构变量,所以指向结构变量的指针自然是结构类型。上述程序只是结点的类型,并不是实际的结点,或者说实际分配存储空间,只有定义了结构变量才会分配存储空间,例如下面的程序则为建立真实的链表:

#include <stdio.h>

struct Student{                 //定义结构类型  //全局变量,main和子函数是处于同一个等级
	int num;
	float score;
	struct Student *next;
};

int main(){
 /*(1)定义各结点*/
	struct Student a,b,c,*head;           
/*(2)初始化各结点的实际数据*/
	a.num =10101;a.score=88.5;               
	b.num =10103;b.score=90;
	c.num =10107;c.score=85;
/*(3)将各结点链接在一起*/	
	head=&a;
	a.next=&b;
	b.next =&c;
	c.next =NULL;
/*打印各结点的实际数据*/	
	struct Student *p=head;                 //1)定义指针指向头指针,头指针不可变,所以不可以使用头指针遍历整个链表
	for(;p!=NULL;p=p->next){                        //2)p=p->next实现p指向每一个结点   //关于for循环的大括号
		printf("%ld %5.1f
",p->num,p->score);    //3)使用->运算符打印输出每个结点数据
	}
	
	return 0;                                     //关于返回值
} 

建立链表需要上述(1)-(3)3个步骤,打印/输出链表则需要1)-3)3个步骤。

课上练习题:

例1:
(1)建立链表,实际数据包括学号,姓名。并使用同一排3名同学的信息进行初始化。
(2)输出3名同学的信息。

#include <stdio.h>
#include <string.h> 

struct Student{
	int num;
	char name[20];
	struct Student *next;
};

int main(){
	struct Student a,b,c,*head;
	a.num =22;strcpy(a.name,"于金池");
	b.num =23;strcpy(b.name,"于港岩");
	c.num =24;strcpy(c.name,"王丫");
	
	head=&a;
	a.next=&b;
	b.next =&c;
	c.next =NULL;
	
	struct Student *p=head;
	for(;p!=NULL;p=p->next){
		printf("%ld %s
",p->num,p->name);
	}
	
	return 0;
} 

例2:
(1)建立链表,实际数据包括学号,姓名。并使用同一排3名同学的信息进行初始化。
(2)建立函数printinfo,参数是结构指针,在该函数中实现输出3名同学的信息。

#include <stdio.h>
#include <string.h> 

struct Student{
	int num;
	char name[20];
	struct Student *next;
};

void printinfo(struct Student *p){
	for(;p!=NULL;p=p->next){
		printf("%ld %s
",p->num,p->name);
	}
} 

int main(){
	struct Student a,b,c,*head;
	a.num =22;strcpy(a.name,"于金池");
	b.num =23;strcpy(b.name,"于港岩");
	c.num =24;strcpy(c.name,"王丫");
	
	head=&a;
	a.next=&b;
	b.next =&c;
	c.next =NULL;
	
	printinfo(head);
	
	return 0;
} 

例3:
(1)建立链表,实际数据包括学号,姓名。并使用同一排3名同学的信息进行初始化。
(2)建立函数searchinfo,参数是结构指针,在该函数中实现输出你自己的信息。

#include <stdio.h>
#include <string.h> 

struct Student{
	int num;
	char name[20];
	struct Student *next;
};

void searchinfo(struct Student *p){
	for(;p!=NULL;p=p->next){
		if(p->num ==22)
		printf("%ld %s
",p->num,p->name);
	}
} 

int main(){
	struct Student a,b,c,*head;
	a.num =22;strcpy(a.name,"于金池");
	b.num =23;strcpy(b.name,"于港岩");
	c.num =24;strcpy(c.name,"王丫");
	
	head=&a;
	a.next=&b;
	b.next =&c;
	c.next =NULL;
	
	searchinfo(head);
	
	return 0;
} 

在上述函数调用中,函数参数是链表头指针,因为通过链表头指针可以访问到链表中的任意结点,因此在定义相关的操作函数时,可以使用头指针作为参数和返回值。

原文地址:https://www.cnblogs.com/c-programing-language/p/6697610.html