单链表逆置(头插法;向后转)

1.单链表的基本结构示意图

2.在写逆置之前需要写的其他基本函数

(1)首先在建立一个"list.h"的头文件,用来放声明

#pragma once
//单链表的结构定义
typedef struct Node
{
	int data;//数据域
	struct Node* next;
}Node, * List;


//初始化
void InitList(List plist);

//尾插
bool Insert_tail(List plist, int val);

//输出
void Show(List plist);

//链表逆置(向后转)
void Reverse1(List plist);

//链表逆置(头插法)
void Reverse(List plist);

(2)接着建立一个"list.cpp"的源文件来实现上面的函数

//初始化
void InitList(List plist)
{
	assert(plist != NULL);
	if (plist == NULL)
		return;
	plist->next = NULL;
	//头节点的数据域不用
}

//尾插
bool Insert_tail(List plist, int val)
{
	assert(plist != NULL);
	if (plist == NULL)
		return false;
	Node* p = (Node*)malloc(sizeof(Node));//p是申请的新节点
	assert(p != NULL);
	p->data = val;
	Node* q;//用来查找尾巴
	for (q = plist; q->next != NULL; q = q->next)
	{
		;
	}
	p->next = q->next;
	q->next = p;
	return true;
}

//输出
void Show(List plist)
{
	assert(plist != NULL);
	if (plist == NULL)
		return;
	for (Node* p = plist->next; p != NULL; p = p->next)
	{
		printf("%d ", p->data);
	}
	printf("\n");
}

//链表逆置(方法一:向后转)
void Reverse1(List plist)
{
	assert(plist != NULL);
	if (plist == NULL || plist->next == NULL || plist->next->next == NULL)
		return;
	Node* p = plist->next;
	Node* q = p->next;
	Node* r;
	p->next = NULL;
	while (q != NULL)
	{
		r = q->next;
		q->next = p;
		p = q;
		q = r;
	}
	plist->next = p;
}

//方法二:头插法
void Reverse(List plist)
{
	assert(plist != NULL);
	if (plist == NULL || plist->next == NULL || plist->next->next == NULL)
		return;
	Node* p = plist->next;
	Node* q = p->next;
	plist->next = NULL;
	while (p != NULL)
	{
		q = p->next;
		p->next = plist->next;
		plist->next = p;
		p = q;
	}
}

(3)最后建立一个"test.cpp"的源文件用来测试两个逆置函数

#include<stdio.h>
#include"list.h"

//单链表逆置测试
int main()
{
	Node head;//定义一个链表
	InitList(&head);//初始化
	for (int i = 0; i < 20; i++)
	{
		Insert_tail(&head, i);//尾插
	}
	printf("原本的链表为:");
	Show(&head);
	Reverse(&head);
	printf("逆置后的链表为:");
	Show(&head);
	return 0;
}

两次运行结果如图所示

3.对“向后转”和“头插法”的详解

(1)向后转(和头插法比较处理比较麻烦)

首先“if (plist == NULL || plist->next == NULL || plist->next->next == NULL)”这个语句是为了 防止给的是空表或者只有一个节点,直接return出去,不会崩溃掉

在这个方法中需要定义三个指针,分别为p,q,r。其中p是前面的点,q是后面的点,r是未处理的点。

“q->next=p”这句话就会让链表的指向方向发生改变;在写这句话之前需要先标记r,因为如果不标记后面的内容就找不到了,如下图所示

接下来r不能直接往后走,三个点应该依次有顺序往后走。顺序为"p=q;q=r;r=q->next;",写完这三句之后再写"q->next=p;"又会出现下一个反转箭头

接着一直往后走,当r走到空的时候仍然没有处理完,需要再写一遍"q->next=p;",写完之后变成

再接着往后走,q就会也等于空,所以循环终止条件是“q==NULL;”,这个时候表示处理完了。但是结束之后头节点的指针还是指向后面,所以需要特殊处理,即“plist->next=p”即可,因为此时p就是最后一个节点

在这张图中你会看到第一个节点的next是100,不符合逆置后的链表,所以在循环进入之前就要对该节点的next进行处理,因为第一个节点逆置之后就是最后一个节点,所以要把第一个节点置空,在p,q,r定义完成之后才能确定位置,否则后面的数据都会消失,语句为“p->next=NULL”。

完成之后就把链表逆置完毕了

(2)头插法

首先“if (plist == NULL || plist->next == NULL || plist->next->next == NULL)”这个语句是为了 防止给的是空表或者只有一个节点,直接return出去,不会崩溃掉

 需要定义两个指针,分别为p,q

定义好之后让链表断开,变成两部分,“plist->next=NULL”,注意不能在没有定义p,q之前就置空,那样后面的数据就会丢失

接着利用头插把p这个节点整体插到plist上,在处理q之前先“p = q;q = p->next;”,按照这样的顺序挪整体

 

发现这个循环结束条件不能是"q==NULL",所以继续处理,p应该作为循环的结束条件,在下一次挪动的时候p为空就结束了

最后就完成了对单链表的逆置

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值