有关链表的操作很多初学者总是望而却步,其实链表的操作关键在于指针的移动顺序,以及清楚理解需要保存的临时指针,理清思路即可。
这里演示了一个有关于单向链表的翻转示例,实现思路其实不难,但是真正写起来的时候回发现很多问题。
定义单链表结构体
1 typedef struct listnode 2 { 3 int value; 4 struct listnode *next; 5 } node;
全旋转单链表常规方法
1 node *convert(node * head) 2 { 3 node * foreNode = NULL; // 当前结点的前一位 4 node * nextNode = NULL; // 当前结点的后一位 5 node * tempNode = NULL; // 当前结点,操作结点 6 if(head == NULL || head->next == NULL) 7 return head; 8 9 nextNode = head->next; 10 tempNode = foreNode = head; 11 int i = 0; 12 while(nextNode != NULL) 13 { 14 head = nextNode; // 更新链表头结点 15 nextNode = head->next; // 更新下一次的头结点 16 tempNode->next = nextNode; // 更新目标链表末尾的结点指向 17 head -> next = foreNode; // 头结点插入 18 foreNode = head; // 头结点保存 19 } 20 return head; 21 22 }
过程分析:示例单链表:1->2->3->4->5
1) 2->1->3->4->5
2) 3->2->1->4->5
3) 4->3->2->1->5
4) 5->4->3->2->1
全翻转单链表递归实现
1 node *reverse(node *head, node *pre) // 作用:将pre连接到head的后面 2 { 3 node *p = head->next; 4 head->next = pre; 5 if(p) 6 return reverse(p, head); 7 else 8 return head; 9 }
以K为半径的单链表翻转
示例:单链表为: 1->2->3->4->5->6->7->8,当K=3时,翻转输出 :3->2->1->6->5->4->7->8
思路:由链表长度和翻转半径给链表进行分组,如8个结点、半径为3则分为2组,完整的2组内进行全翻转,不足半径长度的多余组不翻转,小组翻转完成后将组与组之间进行连接
1 /// 以K为半径的单链表翻转 2 node *convertWithK(node *head , int K) 3 { 4 node * tempNode = head; 5 node * foreNode = head; 6 node * nextNode = NULL; 7 node * foreEnd = NULL; // 用于保存前一组的末结点以便进行连接 8 node * tempEnd = NULL; 9 10 if(!head || !head->next) 11 return head; 12 int i , j; 13 14 // 计算需要移动的组 15 int count = 0; 16 while(tempNode) 17 { 18 count++; 19 tempNode = tempNode->next; 20 } 21 count = count / K; 22 23 tempNode = head; 24 foreEnd = head; 25 26 for(i = 0; i < count; i++) // 分组的循环 27 { 28 29 tempEnd = tempNode; // 当前组翻转后的组末结点,及原组的组头结点 30 foreNode = tempNode; // 更新组首结点 31 tempNode = tempNode->next; // 首位得向后移动一格 32 for(j = 0; j < K - 1; j++) 33 { 34 nextNode = tempNode->next; 35 tempNode->next = foreNode; 36 foreNode = tempNode; 37 tempNode = nextNode; 38 } 39 40 // 连接与前一组的结点 41 if(i == 0) 42 head = foreNode; // 储存返回的头结点 43 // 非第一组的情况 44 if(i) 45 { 46 foreEnd->next = foreNode; 47 foreEnd = tempEnd; 48 } 49 50 // 连接与后一组的结点 51 if(i == count - 1) 52 tempEnd->next = tempNode; 53 } 54 return head; 55 }
至此单链表的翻转已完成,目测算法还不够简洁,复杂度有待优化,望大神指点!