假设单链表的数据结构定义如下:
typedef struct LNode
{
int data;
struct LNode *next;
}LNode, *LinkedList;
并且这个单链表有一个头指针list指向第一个结点,最后一个结点指向NULL,很容易理解。
最容易想到的第一种方法就是重新建立一个单链表newList,每次将list中的第一个结点放到newList后面。注释比较详细,所以就不具体说了,直接看代码吧:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
LinkedList ReverseSinglyLinkedList(LinkedList list)
{
LinkedList newList;//新链表的头结点
LNode *tmp;//指向list的第一个结点,也就是要摘除的结点
//
//参数为空或者内存分配失败则返回NULL
//
if (list
== NULL || (newList = (LinkedList)malloc(sizeof(LNode)))
== NULL)
{
return NULL;
}
//
//初始化newList
//
newList->data
= list->data;
newList->next
= NULL;
//
//依次将list的第一个结点放到newList的第一个结点位置
//
while (list->next
!= NULL)
{
tmp
=
newList->next;//保存newList中的后续结点
newList->next
=
list->next;//将list的第一个结点放到newList中
list->next
=
list->next->next;//从list中摘除这个结点
newList->next->next
=
tmp;//恢复newList中后续结点的指针
}
//
//原头结点应该释放掉,并返回新头结点的指针
//
free(list);
return newList;
}
第二种方法是每次都将原第一个结点之后的那个结点放在list后面,下图是原始的单链表。
第一次交换
第二次交换
为了反转这个单链表,我们先让头结点的next域指向结点2,再让结点1的next域指向结点3,最后将结点2的next域指向结点1,就完成了第一次交换,顺序就变成了Header-结点2-结点1-结点3-结点4-NULL,然后进行相同的交换将结点3移动到结点2的前面,然后再将结点4移动到结点3的前面就完成了反转,思路有了,就该写代码了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
LinkedList ReverseSinglyLinkedList(LinkedList list)
{
LNode *tmp
= NULL;
LNode *p
= NULL;
if (list
== NULL)
{
return NULL;
}
tmp
= list->next;
while (tmp->next
!= NULL)
{
p
= tmp->next;
tmp->next
= p->next;
p->next
= list->next;
list->next
= p;
}
return list;
}
第三种方法跟第二种方法差不多,第二种方法是将后面的结点向前移动到头结点的后面,第三种方法是将前面的结点移动到原来的最后一个结点的后面,思路跟第二种方法差不多,就不贴代码了。
Status ListReverse(LinkList L)
{
LinkList current,pnext,prev;
if(L ==
NULL || L->next == NULL)
return L;
current
= L->next;
pnext =
current->next;
current->next = NULL;
while(pnext)
{
prev =
pnext->next;
pnext->next =
current;
current = pnext;
pnext = prev;
printf("交换后:current = %d,next
= %d \n",current->data,current->next->data);
}
//printf("current = %d,next = %d
\n",current->data,current->next->data);
L->next = current;
return
L;
}