C语言数据结构之单向链表详解分析

 更新时间:2021年11月03日 14:47:07   作者:DDsoup  
链表可以说是一种最为基础的数据结构了,而单向链表更是基础中的基础。链表是由一组元素以特定的顺序组合或链接在一起的,不同元素之间在逻辑上相邻,但是在物理上并不一定相邻。在维护一组数据集合时,就可以使用链表,这一点和数组很相似

链表的概念:链表是一种动态存储分布的数据结构,由若干个同一结构类型的结点依次串连而成。

链表分为单向链表和双向链表。

链表变量一般用指针head表示,用来存放链表首结点的地址。

每个结点由数据部分和下一个结点的地址部分组成,即每个结点都指向下一个结点。最后一个结点称为表尾,其下一个结点的地址部分的值为NULL(表示为空地址)。

特别注意:链表中的各个结点在内存中是可以不连续存放的,具体存放位置由系统分配。

例如:int *ptr ;

因此不可以用ptr++的方式来寻找下一个结点。

使用链表的优点:

不需要事先定义存储空间大小,可以实时动态分配,内存利用效率高;

可以很方便地插入新元素(结点) ,使链表保持排序状态,操作效率高。

下面用课本的例子来讲解:

/*用链表实现学生成绩信息的管理*/ 
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct stud_node{
	int num;
	char name[24];
	int score;
	struct stud_node *next;
};
struct stud_node *Create_Stu_Doc();   /*新建链表*/
struct stud_node *InsertDoc(struct stud_node *head,struct stud_node *stud);   /*插入*/
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;
	char name[20];
	int size = sizeof(struct stud_node);
	
	do{
		printf("1:Create\n 2:Insert\n 3: Delete\n 4:Print\n 0:Exit\n");
		scanf("%d",&choice);
		switch(choice){
			case 1:
			    head = Create_Stu_Doc();
			    break;
			case 2:
				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);
				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;
 } 
/*新建链表*/
struct stud_node *Create_Stu_Doc(){
	struct stud_node *head,*p;
	int num,score;
	char name[20];
	int size = sizeof(struct stud_node);
	
	head = 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;
		head = InsertDoc(head,p);    /*调用插入函数*/
		scanf("%d %s %d",&num,name,&score); 
	}
	return head;
} 
/*插入操作*/
struct stud_node *InsertDoc(struct stud_node *head,struct stud_node *stud){
	struct stud_node *ptr,*ptr1,*ptr2;
	ptr2 = head;
	ptr = stud;             /*ptr指向待插入的新的学生记录结点*/
	/*原链表为空链表时的插入*/
	if(head == NULL){
		head = ptr;
		head->next = NULL;
	}else{
		while((ptr->num > ptr2->num)&&(ptr2->next != NULL)){
			ptr1 = ptr2;
			ptr2 = ptr2->next;         /*ptr1,ptr2各往后移一个结点*/ 
		}                             
		if(ptr->num <= ptr2->num){     /*在ptr1与ptr2之间插入新结点*/ 
			if(head == ptr2){
			head=ptr;
		}
		else{
			ptr1->next = ptr;
			ptr->next = ptr2;
		}
		}
		else{                         
			ptr2->next = ptr;          /*新插入结点成为尾结点*/
			ptr->next =NULL; 
		}
	}
	return head;
} 
/*删除操作*/
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);
	}
	if(head==NULL){
        return NULL;	
	}         /*链表为空*/ 
	/*要被删除结点为非表头结点*/
	ptr1=head;
	ptr2=head->next;      /*从表头的下一个结点搜索所有符合删除要求的结点*/
	while(ptr2 != NULL){
		if(ptr2->num == num)/*ptr2所指结点符合删除要求*/{
			ptr1->next=ptr2->next;
			free(ptr2);
		}
		else{
			ptr1 = ptr2;         /*ptr1后移一个结点*/ 
			ptr2 = ptr1->next;        /*ptr2指向ptr1的后一个结点*/ 
		}
	} 
	return head;
} 
/*遍历操作*/
void Print_Stu_Doc(struct stud_node *head){
	struct stud_node *ptr;
	  if(head==NULL){
	  	printf("\nNo Records\n");
	  	return;
	  }
	  printf("\nThe Students'Records Are:\n");
	  printf("Num\t Name\t Score\t");
	  for(ptr=head;ptr!=NULL;ptr=ptr->next){
	  	printf("%d\t%s\t%d\n",ptr->num,ptr->name,ptr->score);
	  }
} 

申请大小为 struct stud_node 结构的动态内存空间,新申请到的空间要被强制类型转换成

struct stud_node 型的指针,并保存到指针变量p中,如下:

struct stud_node*p;

p = ( struct stud_node *)malloc(sizeof( struct stud_node ));

链表的建立:

上面程序中链表结点是按照学生学号排序的,若向根据数据输入的顺序来建立链表,如下:

/*按输入顺序建立单向链表*/
struct stud_node *Create_Stu_Doc(){
	int num,score;
	char name[20];
	int size = sizeof(struct stud_node);
	struct stud_node *head,*tail,*p;
	head=tail=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;       /*把原来链表的尾结点的next域指向该新增的结点*/
			tail=p;
		}
		scanf("%d %s %d",&num,name,&score);
	}
	return head;
} 

由于按数据输入建立链表时,新增加的结点会加在链表末尾,所以该新增结点的 next 域应置成 NULL : p->next = NULL.

链表的遍历:

为了逐个显示链表每个结点的数据,程序要不断从链表中读取结点内容,显然需要用到循环。

在for语句中将ptr的初值置为表头head,当ptr不为NULL时循环继续,否则循环结束。不可以用ptr++来寻找下一个结点。

链表的插入:

插入原则:先连后断。

首先找到正确位置,然后插入新的结点。寻找正确位置是一个循环的过程:从链表head开始,把要插入的结点stud的num分量值与链表中结点的num分量值逐一比较,直到出现要插入结点的值比第 i 结点的num分量值大,比第 i+1结点的分量值小。所以先与第 i+1 结点相连。再将 i 结点 与 i+1结点断开,并让 i 结点与 stud 结点相连。

链表的删除:

删除原则:先接后删。

若被删除结点是表头则 head=head->next ;

其他内容省略。

到此这篇关于C语言数据结构之单向链表详解分析的文章就介绍到这了,更多相关C语言 单向链表内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++拷贝构造函数(深拷贝与浅拷贝)详解

    C++拷贝构造函数(深拷贝与浅拷贝)详解

    深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝
    2013-09-09
  • C++实现简易万年历

    C++实现简易万年历

    这篇文章主要为大家详细介绍了C++实现简易万年历,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-10-10
  • c语言实现含递归清场版扫雷游戏

    c语言实现含递归清场版扫雷游戏

    扫雷大家应该都玩过,这是一个十分经典的游戏,下面这篇文章主要给大家介绍了关于c语言实现含递归清场版扫雷游戏的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2021-11-11
  • C语言编程中对目录进行基本的打开关闭和读取操作详解

    C语言编程中对目录进行基本的打开关闭和读取操作详解

    这篇文章主要介绍了C语言编程中对目录进行基本的打开关闭和读取操作,是C语言入门学习中的基础知识,需要的朋友可以参考下
    2015-09-09
  • C语言动态内存分配图文讲解

    C语言动态内存分配图文讲解

    给数组分配多大的空间?你是否和初学C时的我一样,有过这样的疑问。这一期就来聊一聊动态内存的分配,读完这篇文章,你可能对内存的分配有一个更好的理解
    2023-01-01
  • 一文详解C语言操作符

    一文详解C语言操作符

    这篇文章主要详细介绍了C语言的操作符,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • C++ sizeof 实例解析

    C++ sizeof 实例解析

    下面5个列子针对C++,没有涉及到sizeof字节对齐及基本数据类型即只针对C++特有,并且针对的是32位机
    2013-07-07
  • C++可以函数重载而C不可以的原因分析

    C++可以函数重载而C不可以的原因分析

    函数重载是指在同一个作用域内,可以定义多个函数,它们具有相同的名称但是参数列表不同,为什么C++可以函数重载而C不可以,接下来就有小编来给大家介绍一下C++可以函数重载而C不可以的原因,需要的朋友可以参考下
    2023-12-12
  • C语言位图算法详解

    C语言位图算法详解

    这篇文章主要介绍了C语言实现的位图算法,主要包括了位图算法的定义与应用,对于C程序算法设计的学习有一定的借鉴价值,需要的朋友可以参考下
    2014-09-09
  • QT自定义QTextEdit实现大数据的实时刷新显示功能实例

    QT自定义QTextEdit实现大数据的实时刷新显示功能实例

    TextEdit是我们常用的Qt控件,用来显示文本信息,下面这篇文章主要给大家介绍了关于QT自定义QTextEdit实现大数据的实时刷新显示功能的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-05-05

最新评论