浅谈C链表(1)

浅谈C链表(1)

首先向大家介绍我写本文的目的。

当我第一次来到CSDN论坛时,便深深的感慨,在IT领域,高手数不胜数。从此IT高手便成为我心向往之的一个称谓。作为一名C语言初学者,我将把我学习C积累的经验和遇到的问题展示给大家,希望CSDN能成为我们之间交流的平台,共同进步,达到心中的目标。 

进入正题。在引入链表之前,我们通常都是用数组来存放数据的,但是使用数组之前要指定数组中包含元素的个数,即数组的长度。如果要向这个数组中加入的元素的个数超过了数组的长度,那么在存放时便会出现错误。比如定义班级人数的时候,如果小班是10人,大班是20人,而定义班级人数的时候使用的是数组,那么定义的长度必须为最大,即20,这样的话很是浪费内存空间。但是链表存储元素的个数是不受限定的,当进行添加元素时,存储的个数就会随之增长,不会出现浪费的现象。

本文介绍的是最简单的单链表的建立,插入、删除与合并将在(2),(3),(4)中介绍。

接下来是我对链表的理解,还望大家多予指正。

链表包含结点与指向关系(指向关系可以理解为连接节点的绳子,由指针实现),节点的创建通常由结构体实现,它包含两个元素,指针域与数据域,数据域存放数据,指针域指向下一个结点,存放下一个结点的地址。

头指针(实际为头结点,由于头结点的数据域为空,只有指针域,故头结点便是头指针)在定义时一般为空。比如一个链表中有三个结点,头指针指向第一个结点,第一个结点的指针指向第二个结点,第二个结点的指针指向第三个结点,第三个结点的指针域为空。所以链表,就像是一个铁链一样,一环扣一环。





图中大家可以很清楚的看到单链表的建立。

例:设计一个链表表示班级中的学生。每一个学生便是一个结点,用指针把每个学生连接起来,便成为一个链表。

struct student
{
int inumber;
char name[20];
struct student* pNext;
};

可见学生这个结点中,存在数据域(姓名和学号)以及指针域,简单的结点就这样创建。

从刚才与数组的比较中得知,数组的大小是一开始便固定好的,而链表的大小则不是,它取决于链表中结点的数量,所以链表的创建过程是一个动态分配内存进而创建的过程。这样便涉及到动态分配内存的函数malloc。

函数原型为:

void *malloc(unsigned int size)

该函数的作用是在内存中动态分配一块大小为size的内存空间,返回的是指针,即返回这块刚分配的内存空间的地址。如果错误返回NULL。

free函数

void free(void *ptr)

用来释放动态分配的内存。(由于动态分配的内存存放在堆区,并非栈区,栈区的内存自动释放,而堆区分配的内存需要手动释放,否则时间久的话内存会崩溃)

下面给出创建一个学生的单链表的代码,之后笔者再逐条解释。

</pre><pre name="code" class="cpp">#include <stdio.h>
#include <stdlib.h>
struct student
{
	int inumber;
	char name[20];
	struct student* pNext;
};
int count=0;//定义全局变量来存放节点的数量
//首先是写创建链表的函数
struct student* Create()
{
	struct student* head=NULL;
	struct student* pNew,*pEnd;
	pNew=pEnd=(struct student*)malloc(sizeof(struct student));//创建一个节点,pNew指针指向它,跟踪指针pEnd指针也指向它
	printf("请输入姓名,学号\n");
	scanf("%s",&pNew->name);
	scanf("%d",&pNew->inumber);
	while(pNew->inumber!=0)
	{
		count++;
		if (count==1)
		{
			pNew->pNext=NULL;
			head=pNew;
		}
		else
		{
			pNew->pNext=NULL;
			pEnd->pNext=pNew;
			pEnd=pNew;        //跟踪指针pEnd,每次都指向一个新的节点
		}
		pNew=(struct student*)malloc(sizeof(struct student));
		scanf("%s",&pNew->name);
		scanf("%d",&pNew->inumber);
	}
	free(pNew);
	return head;
};
//接下来写输出链表的函数
void Print(struct student* head)//参数为什么是头指针head?我是这样理解的:因为读取一个链表中的数据时,总是从头指针开始的,头指针head就像是一个入口。这个头指针便是create函数返回的头指针head。
{
	struct student* temp;
	int index=1;//index存放的是链表中节点的序号
	printf("---这个链表中有%d个成员---\n",count);
	temp=head;//把“入口”的方向赋给临时指针temp,改变temp的指向来输出链表。
	while(temp!=NULL)
	{
		printf("这是第%d个成员\n",index);
		printf("姓名是:%s\n",temp->name);
		printf("学号是:%d\n",temp->inumber);
		printf("\n");
		temp=temp->pNext;
		index++;
	}
}
//由主函数实现
int main(int argc, char *argv[])
{
	struct student* head;
	head=Create();
	Print(head);
	
	return 0;
}

运行程序,结果如下


首先解释创建链表的函数

pNew=pEnd=(struct student*)malloc(sizeof(struct student));

此语句是将调用malloc函数动态创建一块内存区域,并让指针pNew和跟踪指针pEnd同时都指向这块内存空间。

此时输入学生(结点)的数据,判断输入的学号是否为0,若为0则不循环(在执行的时候,将所有学生的信息输入完毕,再输入0便可退出程序)。若不为0则进入循环,将count(表示结点的数量)自加,判断count,如果是1,表示只有一个结点,将pNew的指向赋给头指针head,pNew->pNext为pNew指针指向的结点的指针域,由于只有一个结点,便把这个指针域赋为Null(空);向下执行,执行

pNew=(struct student*)malloc(sizeof(struct student));

继续创建一个新的结点,由pNew指针指向它(pNew先前的指向关系自动断掉),继续由用户输入数据,count再次进行自加,判断count,此时count为2,表示有两个结点,执行else语句,跟踪指针pEnd一开始也是指向第一个结点,要将两个结点连接起来,便要将当前pNew指针的指向赋给pEnd->pNext(第一个结点的指针域),这样结点便连接了,再将pNew的指向赋给跟踪指针pEnd,并把pNew指针指向的新结点的指针域再次赋为空NULL,这样指向关系便构造成功了,再循环再执行直到遇到0便不再循环。


再来解释输出链表的函数
头指针是一个链表的入口,是我们每次读取链表中数据时都要从这里进入。定义一个临时指针temp,将头指针的指向赋给temp(temp现在便是链表的入口,通过改变temp的指向读取数据)。可参见注释。


创建链表函数create返回的是头指针,输出链表的函数参数是头指针,这还是因为头指针是链表的入口,用户操作链表是通过头指针进入,再实现的。


结果如上图。


单链表的建立与输出便介绍到此,合并插入删除将在二、三、四中介绍,文中难免存在错误之处,还请大家不吝指正,谢谢大家。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值