朱有鹏C语言高级---4.9.8-单链表--逆序(单链表的完整程序)(8)

朱有鹏C语言高级---4.9.8-单链表--逆序(8)

什么是链表的逆序?

链表的逆序又叫反向,意思就是把链表中所有的有效节点在链表中的顺序给反过来。

单链表逆序算法分析

(1)当我们对一个数据结构进行一个操作时,我们就需要一套算法。这就是数据结构和算法的关系。

(2)我总结:算法有2个层次。第一个层次是数学和逻辑上的算法;第二个层次是用编程语言来实现算法

(3)从逻辑上来讲,链表的逆序有很多种方法。这些方法都能实现最终的需要,但是效率是不一样的。彼此的可扩展性、容错性等不同。

(4)思路:首先遍历原链表,然后将原链表中的头指针和头结点作为新链表的的头指针和头结点。原链表中的有效节点挨个取出来,采用头插入的方法插入到新链表中即可。

(5)链表的逆序 = 遍历+头插入

扫描二维码关注公众号,回复: 3819882 查看本文章

编程实战(核心函数:reverse_linkedlist())

#include <stdio.h>
#include <strings.h>
#include <stdlib.h>

//构建一个链表节点
struct node
{
	int data;		//有效数据
	struct node *pNext;	//指向下一个节点的指针
};

//作用:创建一个链表的节点
//返回:指针,指针指向我们本函数新创建的一个节点的首地址
struct node * create_node(int data)
{
	struct node *p = (struct node *)malloc(sizeof(struct node));
	if (NULL == p)
	{
		printf("malloc error.\n");
		return NULL;
	}
	//清理申请到的堆内存
	bzero(p, sizeof(struct node));
	//填充节点
	p->data = data;
	p->pNext = NULL;//将来要指向下一个节点的首地址
			//实际操作时将下一个节点malloc返回的指针复制给这个
	return p;
}

//思路:由头指针向后遍历,直到走到原来的最后一个节点。原来最后一个节点里面的pNext是NULL,
//现在我们将它改成new就可以了。添加了之后新节点就变成了最后一个。
//pH:头指针,有链表的头指针才能找到链表。new是一个新的节点
//计算添加了新的节点后共有多少个节点,然后把这个数写进头结点中
void insert_tail(struct node *pH, struct node *new)
{
	int cnt = 0;
	//分两布来完成插入
	//第一步,先找到链表中最后一个节点
	struct node *p = pH;
	while (NULL != p->pNext)
	{
		p = p->pNext;//往后走一个节点
		cnt++;
	}
	
	//第二部,将新节点插入到最后一个节点尾部		
	p->pNext = new;
	pH->data = cnt + 1;
}

//思路:
void insert_head(struct node *pH, struct node *new)
{
	//第1步: 新节点的next指向原来的第一个节点
	new->pNext = pH->pNext;	

	//第2部: 头节点的next指向新节点的地址
	pH->pNext = new;

	//第3步: 头节点中的计数要加1
	pH->data += 1;
}

//遍历单链表,pH为指向单链表的头指针,遍历的节点数据打印出来
void bianli(struct node *pH)
{
	
	//pH->data	//头节点的数据,不是链表的常规数据,不要算进去了	
	//struct node *p = pH;//错误,因为头指针后面是头节点,头节点的数据域是节点个数
	struct node *p = pH->pNext;//直接跨过了头节点,p直接走到第一个节点
	printf("-----开始遍历-----\n");
	while (NULL != p->pNext)//是不是最后一个节点
	{
		printf("node data: %d.\n", p->data);		
		p = p->pNext;	//走到下一个节点,也就是循环增量
	}
	printf("node data: %d.\n", p->data);		
	printf("-----完了-----\n");
}


//遍历单链表,pH为指向单链表的头指针,遍历的节点数据打印出来
void bianli2(struct node *pH)
{
	
	//pH->data	//头节点的数据,不是链表的常规数据,不要算进去了	
	struct node *p = pH;//错误,因为头指针后面是头节点,头节点的数据域是节点个数
	printf("-----开始遍历-----\n");
	while (NULL != p->pNext)//是不是最后一个节点
	{
		p = p->pNext;	//走到下一个节点,也就是循环增量
		printf("node data: %d.\n", p->data);		
	}
	printf("-----完了-----\n");
}

// 从链表pH中删除节点,待删除的节点的特征是数据区等于data
// 返回值:当找到并且成功删除了节点则返回0,当未找到节点时返回-1
int delete_node(struct node *pH, int data)//参数:头指针,节点的数据
{
	//找到这个待删除的节点,通过遍历链表来查找
	struct node *p = pH; 	   //头指针后面是头节点,用来指向当前节点
	struct node *pPrev = NULL; //用来指向当前节点的前一个节点
	
	while (NULL != p->pNext) //是不是最后一个节点
	{
		pPrev = p;    //在p走向下一个节点前先将其保存
		p = p->pNext; //走到下一个节点,也就是循环增量
		//判断这个节点是不是我们要找的那个节点
		if (p->data == data)
		{
			// 找到了节点,处理这个节点
			// 分为2种情况,一个是找到的是普通节点,另一个是找到的是尾节点
			
			// 删除的节点的困难点在于:通过链表的遍历依次访问各个节点,找到这个节点
			// 后p指向了这个节点,但是要删除这个节点关键要操作前一个节点,但是这
			// 时候已经没有指针指向前一个节点了,所以没法操作。解决方案就是增加
			// 一个指针指向当前节点的前一个节点
			if (NULL == p->pNext)
			{
				//尾节点
				pPrev->pNext = NULL;	//原来尾节点的前一个节点变成新尾节点
				free(p);		//释放原来的尾节点的内存
			}
			else
			{
				//普通节点
				//要删除的节点的前一个节点和它的后一个节点相连,这样就把要删除的节点给摘出来了
				pPrev->pNext = p->pNext;
				free(p);
			}			
			// 处理完成之后退出程序
			return 0;
			
		}
	}
	// 到这里还没找到,说明链表中没有我们想要的节点
	printf("没找到这个节点.\n");
	return -1;	
}

//将pH指向的链表逆序
void reverse_linkedlist(struct node *pH)
{
	struct node *p = pH->pNext;	//pH指向头节点,p指向第1个有效节点
	struct node *pBack;		//保存当前节点的后一个节点地址	

	//单链表没有有效节点或者只有一个有效节点时,逆序不用做任何操作,直接返回
	if ((NULL == p) || (NULL == p->pNext))
		return ;
	
	//当链表有2个及2个以上节点时,才需要真正进行逆序操作
	while (NULL != p->pNext)	//是不是最后一个节点
	{
		//原链表中第一个有效节点将是逆序后新链表的尾节点,尾节点的pNext指向NULL
		pBack = p->pNext;	//保存p节点后面一个节点地址
		if (p == pH->pNext)
		{
			// 原链表第一个有效节点
			p->pNext = NULL;
			
		}
		else
		{
			// 原链表的非第1个有效节点
			p->pNext = pH->pNext;//后端挂接
		}
		pH->pNext = p;//前端挂接
		
		//p = p->pNext;	//这样已经不行了,因为p->pNext已经被改过了
		p = pBack;	//走到下一个节点	
	}
	// 循环结束后,最后一个节点仍然缺失
	insert_head(pH, p);	
}

int main(void)
{
	//不能指向NULL,因为尾插法时首先会判断头指针的值p->pNext
	//struct node *pHeader = NULL;	
	//定义头指针,创建头节点。头节点的数据域传的是节点的个数
	struct node *pHeader = create_node(0);//数据定义0表示没放数据	

	insert_tail(pHeader, create_node(11));
	insert_tail(pHeader, create_node(12));
	insert_tail(pHeader, create_node(13));
	insert_tail(pHeader, create_node(14));
	
	bianli2(pHeader);
	
	reverse_linkedlist(pHeader);
	printf("-----逆序后-----\n");
	bianli2(pHeader);

	return 0;
}

猜你喜欢

转载自blog.csdn.net/xiaodingqq/article/details/83143571