倒置链表

        最近看了很多对于链表的操作,对链表的操作无非就是对指针的操作,因此,经常会使人晕头转账,今天跟大家分享一个逻辑不是很复杂,但是对指针的操作较为复杂的一个例子----倒置链表。

        顾名思义,倒置链表就是将一个链表里的数据颠倒过来,使得原来的头成为尾部,原来的尾部变成第一个节点。当然,一个简单的方法,可以每次都取得当前链表的最后一个节点,将其前插到新生成的链表的第一个节点的位置,再将该节点释放,最后把新生成的链表的头结点首地址赋给原先链表的头结点首地址。但是,这样做不管是时间复杂度还是空间复杂度,都是比较高的,而如果可以只更改链表里的每个节点的next成员的指向,效率则会大大提高。

        首先我们分析它的手工过程:我们首先要明确链表里的数值遍历的原理以及各个节点的指向关系。我们用一幅图来清晰地表示。

        完成倒置链表有以下几点需要注意:

        1、我们现在要做的就是使head的值变成#5,#1中next成员的值变为NULL,#2中next成员的值变为#1,#3中next成员的值变为#2... ...同时还要满足能够遍历整个链表,依次更改每一个节点中next的值,不能出现更改后无法找到下一个节点的情况。比如#2的next成员更改为了#1,当希望继续找到#3时,原来next空间中存储的#3的地址值已经被覆盖为#1了,因此就不能继续修改#3中next成员的值了,而且还会造成内存泄漏。

        2、我们发现需要将当前节点的next成员修改为当前节点的前一个节点的首地址,这就要求我们每次修改完能够将当前节点的首地址存储起来。而当前节点的首地址又是它的前驱节点的next成员没有更改时的值。

        3、第一个节点和最后一个节点情况较为特殊,因为第一个节点的next成员被更改为NULL,而末节点的首地址又应该赋值给head。


        知道了以上三点我们就可以开始编程了:

        1、我们需要一个变量now用来遍历链表,而更改这个变量的时机必须在我们修改当前节点的next成员之前。

        2、需要一个用来存储当前节点的前驱节点的地址的变量preNode。

        3、每次应先将preNode的值赋值给now的next成员,再将now的值赋值给preNode。

        4、preNode的初值应为NULL,而不应该是#1,因为我们遍历肯定是从第一个节点开始遍历,第一个节点的前一个节点当然应该是空,这样做,一是符合语义性,二是根据我们之前所说的操作“每次将preNode的值赋值给now的next成员”,可以不用单独处理第一个节点,就能够保证第一个节点的next成员的值为NULL。

        5、在最后,我们应该将now的值赋值给head,因为循环结束时,now的值一定是原先链表的最后一个节点。

具体代码如下:

#include <stdio.h>
#include <malloc.h>

typedef struct NODE{
	int data;
	struct NODE *next;
}NODE;

void initLine(NODE **head);
void destoryLine(NODE **head);
void showLine(NODE *head);
void upSideDownLine(NODE **head);

void upSideDownLine(NODE **head) {
	NODE *now = *head;
	NODE *preNode = NULL;
	NODE *temp;

	while (now != NULL) {
		temp = now->next;
		now->next = preNode;
		preNode = now; 
		now = temp;
	}
	*head = preNode;
}

void showLine(NODE *head) {
	NODE *p;

	printf("\n");
	for (p = head; p != NULL; p = p->next) {
		printf("%d ", p->data);
	}
	printf("\n");
}

void destoryLine(NODE **head) {
	NODE *p;

	if (*head == NULL) {
		return;
	}

	while(*head != NULL) {
		p = *head;
		*head = p->next;
		free(p);
	}
}

void initLine(NODE **head) {
	int num;
	NODE *p = *head;

	if (*head != NULL) {
		return;
	}
	printf("请输入一个数(-1表示结束输入):");
	scanf_s("%d", &num);
	while (num != -1) {
		if (*head == NULL) {
			*head = (NODE *)calloc(1, sizeof(NODE));
			(*head)->data = num;
			p = *head;
		}
		else {
			p->next = (NODE *)calloc(1, sizeof(NODE));
			p->next->data = num;
			p = p->next;
		}
		printf("请输入一个数(-1表示结束):");
		scanf_s("%d", &num);
	}
}

void main(void) {
	NODE *head = NULL;

	initLine(&head);
	showLine(head);
	upSideDownLine(&head);
	showLine(head);
	destoryLine(&head);

	fflush(stdin);
	getchar();
}


猜你喜欢

转载自blog.csdn.net/judy_c/article/details/72832781