`

线性表的链式存储——链表(带源码)

阅读更多
一、为什么要采用链式存储(链表)存在的意义 为什么要采用链式存储:
与数组相比,链式存储(即链表)有如下两个优点:
1、数据元素的个数不确定,随时可能增减。采用固定大小的数组浪费空间。
2、方便排序,对于数组来说,每次插入一个元素都可能导致大量数据的移动。
有缺点吗:
与素族相比,链式存储有一个很大的缺点——读取数据!
对于读取其中指定第N个数据,链表必须从头结点用p = p->next(头结点不存储数据);一直遍历N次或N-1次(头结点存储数据)。所以在需要频繁索取某些指定数据的情况下,牺牲空间为代价换取更优的性能就需要采取数组这种数据结构了。

二、链表的定义和操作
链表的基础——结构体和指针:
懂得结构体,懂得指针,那么学习链表就很简单了。

/*
 * 头结点存储数据,即不带头结点的链表
 */
#include <stdio.h>
#include <stdlib.h>

#define OverFlow -1  //定义OverFlow表示内存溢出
#define OK        0  //定义OK表示成功
#define Error    -2  //定义操作失败的返回值
#define OverFlow -1; //定义OverFlow表示内存溢出
#define OK        0; //定义OK表示成功
#define Error    -2; //定义操作失败的返回值
/* 
 * 首先定义一个数据类型int的别名ElemType,
 * 增强程序的可移植性,注意typedef和define的区别
 */
typedef int ElemType;
/*
 * 紧接着定义链表的节点,其实就是>=1个包含数据
 * 的元素(类型任意)和一个本结构体类型的Next指
 * 针(其值指向链表的下一个节点的地址)
 */
typedef struct node
{
	ElemType data;
	struct node *next;
} Node, *LinkList; 



定义了节点的结构体,我们来进行链表操作的函数编写:
首先来看头结点不存储数据的情况:
我们需要:
1.构造一个空表
    构造空表分两种情况,构造头结点不存储数据的空表和头结点存储数据的空表。
/*
 * 1.构建头结点不存储数据的空表(相对简单)
 * 注意函数参数传递的原理
 */
void Init_LinkList(LinkList *Head_pointer) 
{
	*Head_pointer = NULL;
}


2.插入一个元素(头插)
插入一个元素分三步:第一步,定义节点p并初始化,包括分配空间和赋值;第二步,找准插入位置,一般找到插入点的前一个元素;第三步,p->next赋值(这一定首先进行,进行此步骤不影响链表中任何信息)等一系列链表操作,这是核心部分。
/*
 * 2.插入一个元素(头插)
 * 这时候不需要传入位置的数据,只需要传入头指针和数据
 */
int Insert_First(LinkList *Head_pointer, ElemType x)
{
	Node *p; //这里考虑为什么不用LinkList
	p = (Node *) malloc(sizeof Node);
	if (p == NULL)
		return OverFlow;
	p->data = x;
	
	p->next = *Head_pointer;
	*Head_pointer = p;
	
	return OK;
}


3.查找指定的元素(与数组查找元素效率差不多)
/* 
 * 3.查找指定元素,注意这里用到了LinkList定义数据
 * 因为不是要定义一个节点,只是定义一个指针
 */
LinkList Location_LinkList(LinkList Head, ElemType x)
{
	LinkList p;
	p = Head;
	while(p != NULL)
	{
		if (p->data == x)
			break;
		p = p->next;
	}
	return p;
}


4.删除指定的元素
    这里要注意头结点就是要删除的元素时,操作代码不一样。建立链表时头结点不存入数据的原因就在这里。
/*
 * 4.删除指定的元素
 * 有可能改变头结点的值,所以要传入指针
 * 对头结点就是要删除的元素进行单独处理
 */
int Delete_LinkList(LinkList *Head_pointer, ElemType x)
{
	Node *p, *q;
	p = *Head_pointer;
	if (p->data == x)//考虑头结点就是要删除的元素
	{
		*Head_pointer = (*Head_pointer)->next;
		free(p);
		return OK;
	}
	else
	{
		q = p; p = p->next; //q指向前一个节点,p指向下一个节点
		while(p != NULL)
		{
			if (p->data == x)
			{
				q->next = p->next;
				free(p);
				return OK;
			}
			q = p; p = p->next;
		}
	}
	return Error;
}


5.遍历链表
    其实就是逐个操作链表,操作可以包括打印每个元素,更改每个元素。
    注意如果在linux下面打印中文出现乱码的情况,请更改编码方式。可参考我在163博客中的一篇文章:http://canlynet.blog.163.com/blog/static/25501365200911300521926/

/*
 * 5.遍历线性表,打印每个数据
 * 只需要传入Head的值即可
 * 头结点为空需要打印空表,在linux的超级终端下注意中文编码问题
 */
void Show_LinkList(LinkList Head)
{
	LinkList p = Head;
	int i = 0;
	printf("----链表打印----\n");
	if (p == NULL) //处理头结点为空的情况
		printf("空表\n");
	while (p != NULL)
	{
		printf("[%d]:%d\t", i++, p->data);
		p = p->next;
	}
}


6.清空链表
    清空链表需要传入头结点指针。
/*
 * 6.清空链表
 * 清除到头结点为空的状态,也就是一个空表的状态
 */
void SetNull_LinkList(LinkList *Head_pointer)
{
	LinkList p, q;
	p = *Head_pointer;
	while (p != NULL)
	{
		q = p;
		p = p->next;
		free(q);
	}
}


7.计算链表的长度
    注意算法:从Head计算,指针不为空的总数
/*
* 7.计算链表的长度
* 计算方法:从Head开始,计算指针不为空的个数
*/
int Length_LinkList(LinkList Head)
{
LinkList p = Head;
int sum = 0;
while(p != NULL)
{
sum++;
p = p->next;
}
return sum;
}

8.调用单链表操作的主函数
    看了下面这个主函数,我们基本上能够感受到c语言编写软件的一种方式。
/*
 *8.调用单链表操作的主函数
 */
int main(void)
{
	LinkList Head;
	int i;
	Node *loca;
	ElemType x;
	
	Init_LinkList(&Head);
	do
	{
		printf("\n");
		printf("1---插入一个元素(Insert)\n");
		printf("2---查询一个元素(Locate)\n");
		printf("3---删除一个元素(Delete)\n");
		printf("4---显示所有元素(Show)\n");
		printf("5---计算表的长度(Length)\n");
		printf("6---退出\n");
		scanf("%d", &i);
		switch (i)
		{
			case 1:	printf("请输入要插入的分数:\n");
					scanf("%d", &x);
					if (Insert_First(&Head, x) != OK)
						printf("插入失败\n");
					break;
					
			case 2:	printf("请输入要查询的分数\n");
					loca = Location_LinkList(Head, x);
					if (loca != NULL)
						printf("查询成功\n");
					else
						printf("查询失败\n");
					break;
					
			case 3:	printf("请输入要删除的分数\n");
					scanf("%d", &x);
					if (Delete_LinkList(&Head, x) != OK)
						printf("删除失败\n");
					else
						printf("删除成功\n");
					break;
					
			case 4:	Show_LinkList(Head);
					break;
					
			case 5:	printf("表的长度是:%d", Length_LinkList(Head));
					break;
					
			case 6:	break;
			
			default:	printf("错误选择!请重选");
						break;
		}
	} while (i != 6);
	
	SetNull_LinkList(&Head);
	printf("链表已清空,程序退出...\n");
	
	return 0;
}



附件包括了头结点存储数据(即不带头结点的单向链表的操作源码)和头结点不存储数据(即带头结点的单向循环链表)的链表操作的源码。

【完】
更多关于链表操作的算法请继续关注后面的博客文章...
本文所涉及的代码来自《实用数据结构》谭浩强主编,林小茶编著,清华大学出版社出版,作者已对其中bug进行了修正,如果还有问题,恳请赐教,在此谢过!
0
0
分享到:
评论

相关推荐

    c语言数据结构实验:掌握线性表的链式存储结构 熟练掌握循环链表的存储特征和建立方法,掌握线性表的链式存储结构 下面是源码的txt

    2、已知由单链表表示的线性表中,含有三类字符的数据元素(如:字母、数字和其它字符),设计算法构造三个以循环链表示的线性表,使每一个表中只含同一类的字符,且利用原表中的结点空间作为这三个表的空间。...

    线性表实现源码-java

    总结,"线性表实现源码-java"涉及到Java中对线性表两种常见存储结构——顺序存储(ArrayList)和链式存储(LinkedList)的实现,以及相关的基本操作。这些源码对于学习和理解数据结构及其在Java中的应用具有重要意义...

    链表的实现 各种链表源码

    在本资料包中,“链表的实现 各种链表源码”提供了多种链表实现的源代码,帮助我们深入理解和应用链表。 1. **线性表与链表** 线性表是数据结构的基础,它是由相同类型元素构成的有限序列。链表是线性表的一种存储...

    《数据结构C++版》实验一:线性表的顺序存储结构实验报告

    《数据结构C++版》实验一的目的是让学生深入理解线性表的顺序存储结构,并熟练掌握C++程序设计的基本技巧。在这个实验中,学生需要通过类的定义来实现线性表,数据对象的类型可以自定义。以下是实验涉及的主要知识点...

    线性表C++源码.rar

    在C++中实现线性表,通常有两种方式:顺序存储和链式存储。这个名为"线性表C++源码.rar"的压缩包包含了这两种结构的C++实现,同时使用了模板类,使其具有通用性,适用于多种数据类型。 首先,我们来看顺序存储结构...

    llist2_线性表数据结构_源码.zip

    线性表有两种主要的存储方式:顺序存储和链式存储。顺序存储将所有元素存储在一块连续的内存区域中,通过下标访问元素,通常使用数组来实现;链式存储则通过指针链接各个元素,每个元素包含数据域和指针域,可以不...

    线性表(C语言)源码

    在计算机科学中,线性表可以通过多种方式来实现,如顺序存储结构(数组)或链式存储结构(链表)。本源码主要实现了基于链式存储结构的线性表。 ### 2. C语言中的链式结构 链式结构通过指针将各个节点链接起来形成...

    线性表链式表示及实现源码

    源码实现链式线性表时,首先需要定义节点结构体,例如: ```c typedef struct Node { int data; // 数据域 struct Node* next; // 指针域 } ListNode; ``` 然后可以编写插入、删除、遍历等基本操作的函数。例如...

    c数据结构基本算法-线性表存储的设计与测试

    链式存储结构使用链表来存储线性表中的元素。每个元素都有一个指向下一个元素的指针。在C语言中,链表节点可以定义为: ```c typedef struct Node { int value; // 元素值 struct Node* next; // 指向下一个节点...

    线性表操作 c源码及一些应用

    - **链表(Linked Linear List)**:使用链式存储结构,每个元素(节点)包含数据域和指针域,指针指向下一个元素。插入和删除操作相对高效,但访问速度较慢,因为需要遍历链表。 3. **线性表插入操作**: - **...

    链式线性表

    链式线性表是一种在计算机科学中常见的数据结构,它在内存中不是连续存储的,而是通过节点间的指针连接起来。与数组不同,链式线性表在插入和删除元素时具有较高的灵活性,因为不需要移动大量数据。下面将详细讨论...

    线性表

    线性表可以采用顺序存储或链式存储的方式实现。顺序存储通常使用数组来存放元素,而链式存储则通过链表结构连接元素。下面我们逐一介绍这三个操作: 1. **插入操作(insert_sqlist)**: 插入操作是在线性表中指定...

    数据结构实验一源码:线性表、堆栈和队列的操作与实现

    1、线性表的链表实现:遍历、查找、插入、删除、翻转 2、栈的链式存储结构实现:入栈、出栈 3、队列的链式存储结构的实现:入队、出队 4、线性表、栈和队列的应用实现 二、使用仪器、器材 微机一台,操作系统:Win10...

    数据结构--线性表操作(C源代码)

    顺序存储的线性表通常用数组实现,而链式存储则用链表实现。在这个项目中,我们看到的`SqList.cpp`文件很可能实现了顺序存储的线性表。 2. **C语言**: C语言是一种通用的、面向过程的编程语言,因其简洁和高效而被...

    数据结构~链表、栈、队列的简单操作 源码下载

    线性表的顺序存储(数组)和链式存储(链表)各有优缺点,需要根据实际需求选择合适的数据结构。 "5关于串的作业"可能涵盖字符串的处理,字符串在C语言中可以看作是一种特殊的字符链表,涉及字符串的拼接、查找、...

    基于 C++线性表及其实现 栈和队列及其应用课程实验(实验报告+源码)

    (1)熟悉线性表的基本运算在两种存储结构(顺序结构和链式结构)上的实现,以线性表的各种操作(建立、插入、删除等)的实现为实验重点; (2)通过本次实验帮助学生加深对顺序表、链表的理解,并加以应用; (3)...

    c++语言线性表及应用课程设计报告 .doc

    本课程设计的目标是让学生深入理解线性表的概念,并通过编程实践,熟练掌握线性表在两种存储结构——顺序存储和链式存储上的实现,特别是单链表的操作。 单链表是一种动态数据结构,每个元素(节点)包含数据域和...

    广州大学计算机大四上专业方向课设源码.zip

    (1)该题目要求使用两个链式线性表。一个链表存储当前活动进程,要求使用双向链表,排序要求是按照内存使用自多到少排序。另外一个链表存储已结束进程,要求使用单向链表,按照结束时间离当前时间的关系排序,最近...

    xianxingbiao.rar_线性表 实验

    1. 数据结构定义:如何表示线性表的节点(对于链式存储)或数组(对于顺序存储)。 2. 主要操作的算法实现:插入、删除、查找、更新等操作的详细步骤和伪代码。 3. 时间复杂度分析:针对每种操作,讨论其时间复杂度...

Global site tag (gtag.js) - Google Analytics