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

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

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

链表变量一般用指针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语言 单向链表内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言解字符串逆序和单向链表逆序问题的代码示例

    字符串逆序 上次面试碰到一个单向链表逆序的题目,幸好对字符串逆序比较熟悉,类比做出来了.字符串逆序比较简单,直接上代码: void stringReverse(char* p1,char* p2) { if(p1==p2)return; //swap the value of p1 ,p2 *p1=(*p1)+(*p2); *p2=(*p1)-(*p2); *p1=(*p1)-(*p2); if(p1==p2-1)return; else stringReverse(++p1,--p2); }

  • C语言单向链表的表示与实现实例详解

    1.概述: C语言中的单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始. 链表中最简单的一种是单向链表,它包含两个域,一个信息域和一个指针域.这个链接指向列表中的下一个节点,而最后一个节点则指向一个空值. 如下图所示: 一个单向链表包含两个值: 当前节点的值和一个指向下一个节点的链接 一个单向链表的节点被分成两个部分.第一个部分保存或者显示关于节点的信息,第二个部分存储下一个节点的地址.单向链表只可向一个方向遍历. 链表最基本的结构是在每个节点

  • C语言之单向链表详解及实例代码

    1,单向链简洁. 单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始:链表是使用指针进行构造的列表:又称为结点列表,因为链表是由一个个结点组装起来的:其中每个结点都有指针成员变量指列表中的下一个结点:列表是由结点构成,由head指针指向第一个成为表头的结点而终止于最后一个指向nuLL的指针: 2,例子要求: 根据示例代码中的例子,完成单向链表(single linked list)中的以字符串为数据的链表的插入.删除以及查找,并支持单向链表的反转

  • C语言 单向链表的增删查改快速掌握

    目录 前言 一.创建 二.单向链表的函数声明 三.函数实现 1.创建节点 2.尾插节点 3.头插 4.尾删 5.头删 6.查找节点 7.修改 总结 前言 链表是线性表的链式存储结构,它可以以O(1)的时间复杂度进行插入或者删除,同时由于是链式结构相比顺序表而言,不会存在空间浪费的情况.而链表又分为带头单向链表,不带头单向链表,带头循环链表,不带头循环链表,带头双向循环链表,不带头双向循环链表,带头双向链表,不带头双向链表,总共有八种,其中结构最简单的是不带头单向链表,也是实现起来最容易出错的.并

  • C语言实现无头单向链表的示例代码

    目录 一.易错的接口实现 1.1 新节点开辟函数 1.2 尾插 1.3 尾删 二.常见简单接口 2.1 打印链表 2.2 节点计数器 2.3 判断是否为空链表 2.4 通过值查找节点 2.5 头插 2.6 头删 2.7 在任意节点后插入节点 2.8 在任意节点后删除节点 2.9 销毁链表 三.头文件相关内容 3.1 引用的库函数 3.2 结构体声明 一.易错的接口实现 1.1 新节点开辟函数 由于创建一个新节点是频繁的操作,所以封装为一个接口最佳. 链表节点的属性有:(1)数值.(2)指向下一个

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

    链表的概念:链表是一种动态存储分布的数据结构,由若干个同一结构类型的结点依次串连而成. 链表分为单向链表和双向链表. 链表变量一般用指针head表示,用来存放链表首结点的地址. 每个结点由数据部分和下一个结点的地址部分组成,即每个结点都指向下一个结点.最后一个结点称为表尾,其下一个结点的地址部分的值为NULL(表示为空地址). 特别注意:链表中的各个结点在内存中是可以不连续存放的,具体存放位置由系统分配. 例如:int *ptr ; 因此不可以用ptr++的方式来寻找下一个结点. 使用链表的优点

  • python实现单向链表详解

    本文研究的主要是Python中实现单向链表的相关内容,具体如下. 什么是链表 链表顾名思义就是-链 链表是一种动态数据结构,他的特点是用一组任意的存储单元存放数据元素.链表中每一个元素成为"结点",每一个结点都是由数据域和指针域组成的.跟数组不同链表不用预先定义大小,而且硬件支持的话可以无限扩展. 链表与数组的不同点: 数组需要预先定义大小,无法适应数据动态地增减,数据小于定义的长度会浪费内存,数据超过预定义的长度无法插入.而链表是动态增删数据,可以随意增加. 数组适用于获取元素的操作

  • Java数据结构之单链表详解

    一.图示 二.链表的概念及结构 链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的 . 实际中链表的结构非常多样,以下情况组合起来就有8种链表结构: 单向.双向 带头.不带头 循环.非循环 今天,我们实现的是一个 单向 无头 非循环的链表. 下面是此链表的结构组成. 三.单链表的实现 (1)定义一个节点类型 我们创建一个 ListNode 的类作为节点类型,那么我们如何定义成员属性呢? 通过上面的结构分析,我们需要定义两个成员变量 val --作为该节点的

  • C语言数据结构哈希表详解

    /* * 程序名:hash.c,此程序演示哈希表的实现,数据元素单链表带头结点. * */ #include <stdio.h> #include <stdlib.h> #include <string.h> // 哈希表中数据元素的结构体. typedef struct Element { unsigned int key; // 关键字. int value; // 数据元素其它数据项,可以是任意数据类型. // char value[1001]; // 数据元素其

  • C语言数据结构之二分法查找详解

    问题:在有序数组中查找给定元素的下标goal. 在查找一个数组元素的下标,可以用循环来解决,但是如果一个数足够大,比如说手机的价格,用循环来查找,就相当于叫一个人猜,从0开始,需要猜很久.这时候就出现了二分查找,也叫对半查找. 对半查找顾名思义就是猜一次,下次猜的内容就减少一半              这时候定义一个变量left表示最左边元素的下标,在定义一个right表示最右边元素的下标,而mid就表示中间元素的下标. 当中间值小于目标值,left重新定义. if (mid < goal)

  • C语言实现无头单链表详解

    目录 链表的结构体描述(节点) 再定义一个结构体(链表) 断言处理 & 判空处理 创建链表 创建节点 头插法 打印链表 尾插法 指定位置插入 头删法 尾删法 指定位置删除 查找链表 删除所有指定相同的元素 总结 再封装的方式,用 c++ 的思想做无头链表 链表的结构体描述(节点) #include <stdio.h> #include <stdlib.h> #include <assert.h> typedef int DataType; //节点 typede

  • Go语言数据结构之插入排序示例详解

    目录 插入排序 动画演示 Go 代码实现 总结 插入排序 插入排序,英文名(insertion sort)是一种简单且有效的比较排序算法. 思想: 在每次迭代过程中算法随机地从输入序列中移除一个元素,并将改元素插入待排序序列的正确位置.重复该过程,直到所有输入元素都被选择一次,排序结束. 插入排序有点像小时候我们抓扑克牌的方式,如果抓起一张牌,我们放在手里:抓起第二张的时候,会跟手里的第一张牌进行比较,比手里的第一张牌小放在左边,否则,放在右边. 因此,对所有的牌重复这样的操作,所以每一次都是插

  • Go语言数据结构之二叉树可视化详解

    目录 题目 源代码 做题思路 扩展 左右并列展示 上下并列展示 总结回顾 题目 以图形展示任意二叉树,如下图,一个中缀表达式表示的二叉树:3.14*r²*h/3 源代码 package main import ( "fmt" "io" "os" "os/exec" "strconv" "strings" ) type any = interface{} type btNode struc

  • C语言程序环境和预处理详解分析

    目录 一.程序的翻译环境和运行环境 程序的翻译环境 链接阶段 执行环境(运行环境) 二.预处理详解 预定义符号 #define定义标识符 #define定义宏 #define 替换规则 #和##两个预处理的工具 带副作用的宏参数 宏和函数对比 #undef移除宏 命令行定义 条件编译 头文件包含 嵌套文件包含 总结 一.程序的翻译环境和运行环境 重点:任何ANSI C(标准C的程序)的一种实现,存在两个不同的环境 第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令. 第2种是执行环境,

随机推荐