C语言数据结构单链表之温故而知新

简介: 抛弃繁杂的定义,以实用,实战的角度来学习数据结构,这将使得数据结构的学习非常的简单。前面已经学习了单链表的创建操作:http://blog.csdn.net/morixinguan/article/details/68951912这节,将单链表温习的笔记共享出来,然后写一个例子,以防自己忘记。

抛弃繁杂的定义,以实用,实战的角度来学习数据结构,这将使得数据结构的学习非常的简单。

前面已经学习了单链表的创建操作:http://blog.csdn.net/morixinguan/article/details/68951912

这节,将单链表温习的笔记共享出来,然后写一个例子,以防自己忘记。

1、单链表的数据结构的定义:


创建节点函数原型可定义如下:

struct list *create_node(int data) ;
如何创建单链表的节点,主要分以下步骤:
(1)给当前的每个节点的数据结构配置定量的空间大小
   ep : struct list *node = malloc(sizeof(struct list));
(2)清节点数据(由于结构体变量在未初始化的时候,数据是脏的)
   ep : memset(node,0,sizeof(struct list));
(3)给节点初始化数据
   ep : node->id = data ; 
(4)将该节点的指针域设置为NULL
   ep : node->next = NULL ;
3、单链表的尾插:
尾插节点函数原型可定义如下:


如何将当前链表和新的节点相连接?只要实现:
header->next = new 

尾插流程如下:

(1)获取当前节点的位置,也就是访问头节点
   ep : struct list *p = header ;
(2)判断是否为最后一个节点,如果不是,移动到下一个节点,如果是,将数据插入尾部。
   ep : while(NULL != p->next) p = p->next ;
	    p->next = new ;
4、单链表的头插


很好理解,头插就是把新的节点插在原来的节点和原来节点的下一个节点之间的一个节点。如图,新的节点插在头节点和节点1。
所以可以推出头插流程如下:

(1)获取当前节点的位置,也就是访问头节点
	ep : struct list *p = header ;
(2)新的节点的下一个节点设置为原来头节点的下一个节点(第一个节点)
    ep : new->next = p->next ;
(3)原来的头节点的下一个节点设置为现在新插入的头节点
	ep : p->next = new ;
5、单向链表的遍历


      如图为一条单向链表的模型,看图知道该链表由头节点和若干个节点组成,最后一个节点(尾节点)为NULL 。
从图中可以得出信息,如果我们要打印出各个节点的数据,要考虑以下问题:

(1)需要打印头节点吗?(头节点肯定是不用打印的,因为这是我们为了操作方便而设置的一个节点)。
(2)这条链表有多少个节点我们怎么知道?(通过判断该链表是否已经到达了尾节点,标志就是NULL)
那么可以得到流程如下:

(1)获取当前节点的位置,也就是访问头节点
	ep : struct list *p = header ;
(2)由于头节点我们不需要去打印它,这时候,初始化打印的节点需要从第一个节点开始。
	ep : p = p->next ;  
(3)判断是否为最后一个节点,如果不是,先打印第一个节点的数据(1),然后移动到下一个节点(2),重复这两个步骤。
   如果是最后一个节点,直接打印数据即可。
	while(NULL != p->next){ printf("node:%d\n",p->data) ; p = p->next ;}
	printf("node:%d\n",p->data);
	当然还可以一句代码解决,这样就达到了先偏移,后取数据。
	while(NULL != p->next){ p = p->next ; printf("node:%d\n",p->data) ; }
6、单向链表的删除

删除节点的函数原型可定义如下:
int detele_list_node(struct list *pH , int data);
单向链表的删除要考虑两种情况,一种的普通节点的删除(当然,头节点不能算)
还有一种是尾节点的前一个节点的删除情况,注意,删除完节点还需要释放对应节点的内存空间。



删除节点的设计流程:
(1)先定义两个指针,一个表示当前的节点,另一个表示当前节点的上一个节点。
	ep : struct list *p = header ;  //当前节点
		 struct list *prev = NULL ; //当前节点的上一个节点
(2)遍历整个链表,同时保存当前节点的前一个节点
    ep : while(NULL != p->next)
		{ 
		  //保存了当前的节点的前一个节点
		  prev = p ;  
		  //保存当前偏移的节点
		  p = p->next ; 
		  return 0 ;
		}
(3)在遍历的过程中查找要删除的数据
	ep : while(NULL != p->next)
		{ 
		  //保存了当前的节点的前一个节点
		  prev = p ;  
		  //保存当前偏移的节点
		  p = p->next ; 
		  //查找到了数据
		  if(p->id == data)
		  {
		  
		  }
		  return 0 ;
		}
(4)查找到了数据后,分两种情况删除
	ep : 普通节点的删除
		if(p->id == data)
		{
			prev->next = p->next ;
			free(p);
		}
	ep : 考虑尾节点的下一个节点为NULL的节点删除
		if(p->id == data)
		{
			if(p->next == NULL)
			{
				prev->next = NULL ;
				free(p);
			}
		}
5、单向链表的逆序操作


逆序步骤:


流程咱们基本搞懂了,下面写一个程序,这将会变得非常非常的简单。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct slist
{
	int id ;
	struct slist *next ;			
}L;

//创建一个节点 
L *create_node(int data)
{
	//给每个节点分配结构体一样的空间大小 
	L *p = malloc(sizeof(L));
	if(NULL == p)
	{
		printf("malloc error!\n");
		return NULL ;
	}
	//由于结构体在未初始化的时候一样是脏数据,所以要清 
	memset(p,0,sizeof(L));
	//初始化第一个节点 
	p->id = data ; 
	//将节点的后继指针设置为NULL 
	p->next = NULL ;
}

//链表的尾插 
void tail_insert(L *pH , L *new)
{
	//获取当前的位置 
	L *p = pH ; 
	//如果当前位置的下一个节点不为空 
	while(NULL != p->next)
	{
		//移动到下一个节点 
		p = p->next ;
	}
	//如果跳出以上循环,所以已经到了NULL的这个位置
	//此时直接把新插入的节点赋值给NULL这个位置 
	p->next = new ;
}

//链表的头插 
void top_insert(L *pH , L *new)
{
	L *p = pH ;
	new->next = p->next ;
	p->next = new ;
}

//链表的遍历 
void Print_node(L *pH)
{
	//获取当前的位置 
	L *p = pH ;
	//获取第一个节点的位置 
	p = p->next ;
	//如果当前位置的下一个节点不为空 
	while(NULL != p->next)
	{
		//(1)打印节点的数据 
		printf("id:%d\n",p->id);
		//(2)移动到下一个节点,如果条件仍为真,则重复(1),再(2) 
		p = p->next ;
	}
	//如果当前位置的下一个节点为空,则打印数据
	//说明只有一个节点 
	printf("id:%d\n",p->id);
}

//删除链表中的节点 
int detele_list_node(L * pH , int data)
{
	//获取当前头节点的位置 
	L *p = pH ;
	L *prev = NULL;
	while(NULL != p->next)
	{
		//保存当前节点的前一个节点的指针 
		prev = p ;
		//然后让当前的指针继续往后移动 
		p = p->next ; 	
		//判断,找到了要删除的数据  
		if(p->id == data)
		{
			//两种情况,一种是普通节点,还有一种是尾节点
			if(p->next != NULL)  //普通节点的情况 
			{
				prev->next = p->next ;
				free(p);
			}
			else //尾节点的情况 
			{
				prev->next = NULL ; //将这个尾节点的上一个节点的指针域指向空 
				free(p); 
			}
			return 0  ;
		}
	}
	printf("没有要删除的节点\n");
	return -1 ;
}

void trave_list(L * pH)
{
	//保存第一个节点的位置 
	L *p = pH->next;
	L *pBack;
	int i = 0 ;
	if(p->next == NULL || p == NULL)
		return ;
		
	while(NULL != p->next) //遍历链表 
	{
		//保存第一个节点的下一个节点 
		pBack = p->next ; 
		//找到第一个有效节点,其实就是头指针的下一个节点 
		if(p == pH->next) 
		{
			//第一个有效节点就是最后一个节点,所以要指向NULL 
			p->next = NULL ; 
		} 
		else
		{
			/*
			new->next = p->next ;
			p->next = new ;
			*/
			p->next = pH->next ; //尾部连接 
		}
		pH->next = p ; //头部连接 
		p = pBack ; //走下一个节点 
	}
	top_insert(pH,p); //插入最后一个节点 
}

int main(int argc , char **argv) 
{
	//创建第一个节点 
	int i ;
	L *header = create_node(0); 
	for(i = 1 ; i < 10 ; i++)
	{
		tail_insert(header,create_node(i));
	}
	Print_node(header);
	detele_list_node(header,5);
	putchar('\n');
	Print_node(header);
	putchar('\n');
	trave_list(header);
	Print_node(header);
	return 0 ;
}
运行结果:













目录
相关文章
|
10月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
377 1
|
7月前
|
存储 机器学习/深度学习 算法
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
186 30
|
7月前
|
存储 算法 C语言
C 408—《数据结构》算法题基础篇—链表(上)
408考研——《数据结构》算法题基础篇之链表(上)。
288 25
|
7月前
|
定位技术 C语言
c语言及数据结构实现简单贪吃蛇小游戏
c语言及数据结构实现简单贪吃蛇小游戏
|
8月前
|
搜索推荐 C语言
数据结构(C语言)之对归并排序的介绍与理解
归并排序是一种基于分治策略的排序算法,通过递归将数组不断分割为子数组,直到每个子数组仅剩一个元素,再逐步合并这些有序的子数组以得到最终的有序数组。递归版本中,每次分割区间为[left, mid]和[mid+1, right],确保每两个区间内数据有序后进行合并。非递归版本则通过逐步增加gap值(初始为1),先对单个元素排序,再逐步扩大到更大的区间进行合并,直至整个数组有序。归并排序的时间复杂度为O(n*logn),空间复杂度为O(n),且具有稳定性,适用于普通排序及大文件排序场景。
|
8月前
|
机器学习/深度学习 存储 C++
【C++数据结构——线性表】单链表的基本运算(头歌实践教学平台习题)【合集】
本内容介绍了单链表的基本运算任务,涵盖线性表的基本概念、初始化、销毁、判定是否为空表、求长度、输出、求元素值、按元素值查找、插入和删除数据元素等操作。通过C++代码示例详细解释了顺序表和链表的实现方法,并提供了测试说明、通 - **任务描述**:实现单链表的基本运算。 - **相关知识**:包括线性表的概念、初始化、销毁、判断空表、求长度、输出、求元素值、查找、插入和删除等操作。 - **测试说明**:平台会对你编写的代码进行测试,提供测试输入和预期输出。 - **通关代码**:给出了完整的C++代码实现。 - **测试结果**:展示了测试通过后的预期输出结果。 开始你的任务吧,祝你成功!
315 5
|
9月前
|
数据库
数据结构中二叉树,哈希表,顺序表,链表的比较补充
二叉搜索树,哈希表,顺序表,链表的特点的比较
数据结构中二叉树,哈希表,顺序表,链表的比较补充
|
9月前
|
存储 算法 C语言
【C语言】深入浅出:C语言链表的全面解析
链表是一种重要的基础数据结构,适用于频繁的插入和删除操作。通过本篇详细讲解了单链表、双向链表和循环链表的概念和实现,以及各类常用操作的示例代码。掌握链表的使用对于理解更复杂的数据结构和算法具有重要意义。
2779 6
|
10月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
262 5
|
10月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
245 1