6-1 单链表逆转
分数 20
全屏浏览
切换布局
作者 陈越
单位 浙江大学
本题要求实现一个函数,将给定的单链表逆转。
函数接口定义:
List Reverse( List L );
其中List
结构定义如下:
typedef struct Node *PtrToNode;
struct Node {
ElementType Data; /* 存储结点数据 */
PtrToNode Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */
L
是给定单链表,函数Reverse
要返回被逆转后的链表。
裁判测试程序样例:
#include <stdio.h>
#include <stdlib.h>
typedef int ElementType;
typedef struct Node *PtrToNode;
struct Node {
ElementType Data;
PtrToNode Next;
};
typedef PtrToNode List;
List Read(); /* 细节在此不表 */
void Print( List L ); /* 细节在此不表 */
List Reverse( List L );
int main()
{
List L1, L2;
L1 = Read();
L2 = Reverse(L1);
Print(L1);
Print(L2);
return 0;
}
/* 你的代码将被嵌在这里 */
思路:
红箭头与蓝箭头都代表指针指向,他们指向的元素类型一致,因此可以互相赋值,但是它们所包含的内容又不同,所以用不同颜色加以区分。红箭头表当前整个结构整体,恰巧第一个蓝箭头就是该红箭头所指元素包含的一部分。
整体代码调试
#include<stdio.h>
#include<stdlib.h>
typedef int ElementType;
typedef struct Node *PtrToNode;
struct Node {
ElementType Data;
PtrToNode Next;
};
typedef PtrToNode List;
List Read();
void Print(List L);
List Reverse(List L);
int main()
{
List L1, L2;
L1 = Read();
L2 = Reverse(L1);
Print(L1);
Print(L2);
return 0;
}
/* 建立链表 */
List Read()
{
List head = NULL;
List current;
List prev = NULL;
int len = 0;
scanf("%d", &len);
if (len == 0) return NULL;
while (len--)
{
current = (List)malloc(sizeof(struct Node));
if (head == NULL)
head = current;
else
prev->Next = current;
current->Next = NULL;
scanf("%d", ¤t->Data);
prev = current;
}
return head;
}
void Print(List L)
{
List p = L;
List s = L;
List temp;
if (p == NULL)
printf("NULL");
else
printf("\n");
while (p!=NULL) {
printf("%d ", p->Data);
p = p->Next;
}
}
List Reverse( List L )
{
List Temp, Prev;
Prev = NULL;
while(L)
{
Temp = L->Next;
L->Next = Prev;
Prev = L;
L = Temp;
}
return Prev;
}
问题:
会有疑问1是哪里来的
t
通过观察可以看出,是print(L1)打印出的多的1和换行,也就是说移动完后L1即原链表并不是空,还有一个,就是头指针指向的那个。注意通过建立链表中第一个结点与其他结点的不同就可得出此建立的链表中并没有头节点,如果有所有结点都是相同的,只是在最开始就会申请一个结点的空间给头节点,并使头节点的指针域指向为空,头指针指向头节点。
再来仔细看代码
L1 = Read();
L2 = Reverse(L1);
Print(L1);
Print(L2);
List Reverse( List L )
{
List Temp, Prev;
Prev = NULL;
while(L)
{
Temp = L->Next;
L->Next = Prev;
Prev = L;
L = Temp;
}
return Prev;
}
- 观察我们可以发现,在转换时我们传入的是头指针本身,而非头指针的地址,这里是调用函数,因为传入的不是地址,所以并不能改变其本身,顶多就是创建了一个副本,在调用函数中改变副本,一旦调用结束回到主函数,该副本就会消失
- 综上就是说头指针的指向根本不会发生改变,因此仍然指向第一个元素1,所以会输出
- 至于后面的为什么又变了呢:
- 因为传入的头指针指向下一个元素,该元素包含数据域与指针域,且头指针是该元素的地址,也就是说该调用函数可以改变该被指向元素所包含的指针域,因此后面的指针都被改变没有被输出。