倒置链表
来源:互联网 发布:淘宝卖小饰品 编辑:程序博客网 时间:2024/04/27 21:26
最近看了很多对于链表的操作,对链表的操作无非就是对指针的操作,因此,经常会使人晕头转账,今天跟大家分享一个逻辑不是很复杂,但是对指针的操作较为复杂的一个例子----倒置链表。
顾名思义,倒置链表就是将一个链表里的数据颠倒过来,使得原来的头成为尾部,原来的尾部变成第一个节点。当然,一个简单的方法,可以每次都取得当前链表的最后一个节点,将其前插到新生成的链表的第一个节点的位置,再将该节点释放,最后把新生成的链表的头结点首地址赋给原先链表的头结点首地址。但是,这样做不管是时间复杂度还是空间复杂度,都是比较高的,而如果可以只更改链表里的每个节点的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();}
- 链表倒置
- 链表的倒置
- 链表倒置
- 链表倒置
- 链表倒置
- 实现链表倒置
- 链表倒置(逆序)
- 链表的倒置
- [笔试]链表倒置
- 链表的倒置
- 倒置链表
- 链表倒置
- 链表倒置
- 倒置链表
- 链表倒置
- 链表倒置
- 链表的倒置
- 链表的倒置
- lstat函数和S_ISDIR 、S_ISLNK等几个常见的宏
- 交换两个数的位置
- FireBird数据库和管理工具IBExpert及执行sql语句
- Unity原型开发速通
- Java 数据库系列教程--DBCP连接池连接数据库
- 倒置链表
- Linux内核定时器--timer_list
- BZOJ1087互不侵犯king
- 笔记Effective objective-C 2.0之了解Objective-C
- Java如何将List集合中的某些数据放到List集合的首位
- 兴趣爱好
- 运算符重载(1)
- [BZOJ1563]诗人小G(1d1d动态规划)
- Ubuntu安装MySQL