#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
typedef int data_t;
typedef struct node
{
data_t data;//成员数据类型
struct node* next;//存放下一节点地址
}listnode, *linklist;
//将链表指定部分翻转
int link_reverse(linklist p, int origin, int terminal);
头文件LinkList.h
#include "LinkedList.h"
int main()
{
linklist p;
p = link_creat();
//测试部分
int val = 0;
for (data_t i = 1; i < 6; i++)
{
link_insert(p, i, &i);
}
link_show(p);
printf("#######\n\n");
link_reverse(p, 0, 1);
link_show(p);
//
return 0;
}
测试文件test.c
#include "LinkedList.h"
int link_reverse(linklist p, int origin, int terminal)
{
if (p == NULL)
{
printf("Pointer is NULL.\n");
return -1;
}
if (origin < 1 || origin >= terminal)
{
printf("Input Error.\n");
//输入区间的起点过小
//输入区间的起点大于等于终点
return -1;
}
int i = 0;
linklist head = p;
linklist tail = p;
linklist temp;
linklist rest;
for (int i = 0; i < terminal; i++)
{
tail = tail->next;
if (tail == NULL)
{
printf("Input Error.\n");
//输入区间的终点过大
return -1;
}
}
rest = tail->next;
tail->next = NULL;
for (int i = 0; i < origin - 1; i++)
{
head = head->next;
}
temp = head->next;
head->next = NULL;
while (i < terminal - origin + 1)
{
tail = temp;
while (1)
{
if (tail->next == NULL)
{
head->next = tail;
tail->next = rest;
break;
}
else if (tail->next->next == NULL)
{
head->next = tail->next;
head = head->next;
tail->next = NULL;
break;
}
else
{
tail = tail->next;
}
}
i++;
}
return 0;
}
函数实现LinkList.c
实现原理:
拿1-> 2-> 3-> 4-> 5的单链表举例,将第2个到第4个节点进行翻转。
图中p->next是该单链表的头结点,指向该单链表的第一个结点1(p指向的其实是一个数据域为0的结点,这个结点的指针域存放的是这个单链表头结点)
要将第2个到第4个节点进行翻转分为以下三步:
1. 将该单链表待翻转的部分与剩余部分断开。剩余部分分为两部分,指针head指向剩余部分的前半部分最后一个结点,指针rest指向剩余部分的后半部分第一个结点。指针temp指向待翻转部分的第一个结点。
2. 将待翻转部分的最后一个结点连接到剩余部分的前半部分
这个过程中使用了一个指针tail来定位待翻转部分的最后一个结点,该指针初始化时与temp指针指向同一结点然后不断后移直到指向最后一个结点
3. 将head指针重新指向前半部分的最后一个结点,开始新一次的循环
当temp指向的已经是待翻转部分的最后一个元素时,翻转就已经到了最后一步,将三部分依次连接即完成翻转。
这种方法虽然比较麻烦,但很容易理解,可以在不开辟新的动态空间条件下完成翻转。
运行效果如下(其余的函数功能实现在我的上一篇博客中 数据结构单链表C语言实现)
首先生成了一个1-> 2-> 3-> 4-> 5的单链表,通过link_reverse函数将该单链表的第2到第4个节点进行翻转。
将整个链表进行翻转