中国大学MOOC-数据结构基础习题集、02-1、Reversing Linked List
首先先贴一下题目:
Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elements on L. For example, given L being 1→2→3→4→5→6, if K = 3, then you must output 3→2→1→6→5→4; if K = 4, you must output 4→3→2→1→5→6.
Input Specification:
Each input file contains one test case. For each case, the first line contains the address of the first node, a positive N (<= 105) which is the total number of nodes, and a positive K (<=N) which is the length of the sublist to be reversed. The address of a node is a 5-digit nonnegative integer, and NULL is represented by -1.
Then N lines follow, each describes a node in the format:
Address Data Next
where Address is the position of the node, Data is an integer, and Next is the position of the next node.
Output Specification:
For each case, output the resulting ordered linked list. Each node occupies a line, and is printed in the same format as in the input.
Sample Input:
00100 6 4
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218
Sample Output:
00000 4 33218 33218 3 12309 12309 2 00100 00100 1 99999 99999 5 68237 68237 6 -1
输入:
第一行:链表的首地址add,结点个数n,每隔k个进行一次反转。
接下来的n行:结点的地址address,数据data,下一个结点的地址next。
输出:
反转之后的结果。
建议测试如下几个情况:
1. k=1或者k=n:
00100 6 6
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218
2. 有其他链表干扰(即有多个-1出现):
00100 6 2
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 -1
99999 5 68237
12309 2 33218
先说一下我的解题思路吧:
1. 首先要处理输入数据。我是用C++中的容器(vector),容器内存储的类型是新建的类Node。
1 class Node 2 { 3 public : 4 int address; 5 int data; 6 int next; 7 Node* nextNode; 8 Node(int a = 0, int d = 0, int n = 0): 9 address(a), data(d), next(n) 10 { 11 nextNode = NULL; 12 } 13 }; 14 int main() 15 { 16 int add, n, k; 17 cin >> add >> n >> k; 18 vector<Node> vec; 19 // input the data 20 for(int i=0; i<n; i++) 21 { 22 int inputa, inputb, inputc; 23 cin >> inputa >> inputb >> inputc; 24 Node node(inputa, inputb, inputc); 25 vec.push_back(node); 26 } 27 // ... 28 }
2. 这里首先要进行一个预处理,就是按照address对vector内的数据进行升序排序。这么做是为了能增快程序的运行速度,以便通过测试用例5。
1 // define before main 2 bool cmp(const Node &a,const Node &b) 3 { 4 return a.address < b.address; 5 } 6 int main(){ 7 // ... 8 sort(vec.begin(), vec.end(), cmp); 9 }
3. 然后要处理数据,把vecotr内的数据组成单链表。ncount是链表有效结点的数目,p用来遍历myList,q用来遍历myNewList(即反转后的链表)。处理的过程如下:在vector内不断的寻找address为add(即链表头),找到之后放到MyList,然后让it->next成为新的add。不断重复此过程,直到it->next为-1(即链表尾)为止。上面的预处理在这里就起到作用了,如果没有按照address进行升序排序,这个过程会很慢,通不过测试用例。
用while(1)循环,并且当it走到vector的end再让它回到begin,成一个环状。一定会有it->next为-1走出循环,所以不必担心死循环问题。
1 Node* myList = new Node(); 2 int ncount = 0; 3 Node *p = NULL; 4 Node *q = NULL; 5 // deal the data from vector to list 6 vector<Node>::iterator it = vec.begin(); 7 while(1) 8 { 9 // find the first node 10 if(it->address == add) 11 { 12 if(myList->nextNode == NULL) 13 { 14 p = myList->nextNode = new Node(it->address, it->data, it->next); 15 } 16 else 17 { 18 p = p -> nextNode = new Node(it->address, it->data, it->next); 19 } 20 ncount ++; 21 if(it -> next == -1) 22 break; 23 else 24 add = it -> next; 25 } 26 it++; 27 if(it == vec.end()) 28 it = vec.begin(); 29 }// for
4. 接下来就是反转了,具体的我已经写到注释里了,如果有看不懂的地方可以再评论区里发表评论。
1 // if the k greater than effective data, then output all 2 if(k>ncount) 3 { 4 p = myList; 5 while(p->nextNode != NULL) 6 { 7 p = p -> nextNode; 8 if(p->next != -1) 9 printf("%.5d %d %.5d\n", p->address, p->data, p->next); 10 else 11 printf("%.5d %d -1\n", p->address, p->data); 12 } 13 }// if 14 else 15 { 16 Node *myNewList = new Node(); 17 // 借助栈来完成反转 18 stack<Node*> sta; 19 // 需要反转几次 20 int times = ncount/k; 21 // p始终指向MyList 22 p = myList; 23 // q始终指向MyNewList 24 q = myNewList; 25 // 进行times次反转 26 for(int j=0; j<times; j++) 27 { 28 for(int m=0; m<k; m++) 29 { 30 p = p -> nextNode; 31 sta.push(p); 32 } 33 for(int m=0; m<k; m++) 34 { 35 Node *qt = sta.top(); 36 sta.pop(); 37 if(myNewList->nextNode == NULL) 38 { 39 q = myNewList->nextNode = new Node(qt->address, qt->data, qt->next); 40 } 41 else 42 { 43 q = q -> nextNode = new Node(qt->address, qt->data, qt->next); 44 } 45 } 46 } // for 47 // 将剩下的节点依次插入到myNewList后面 48 while(p -> nextNode != NULL) 49 { 50 p = p -> nextNode; 51 if(myNewList->nextNode == NULL) 52 { 53 q = myNewList->nextNode = new Node(p->address, p->data, p->next); 54 } 55 else 56 { 57 q = q -> nextNode = new Node(p->address, p->data, p->next); 58 } 59 } // while 60 // 输出 61 p = myNewList; 62 while(p->nextNode != NULL) 63 { 64 p = p -> nextNode; 65 if (p->nextNode != NULL) 66 p->next = p->nextNode -> address; 67 else 68 p->next = -1; 69 if(p->next != -1) 70 printf("%.5d %d %.5d\n", p->address, p->data, p->next); 71 else 72 printf("%.5d %d -1\n", p->address, p->data); 73 } // while
5. 完整的代码如下:
1 #include <iostream> 2 #include <vector> 3 #include <cstdlib> 4 #include <iomanip> 5 #include <cstdio> 6 #include <stack> 7 #include <algorithm> 8 using namespace std; 9 10 class Node 11 { 12 public : 13 int address; 14 int data; 15 int next; 16 Node* nextNode; 17 Node(int a = 0, int d = 0, int n = 0): 18 address(a), data(d), next(n) 19 { 20 nextNode = NULL; 21 } 22 }; 23 bool cmp(const Node &a,const Node &b) 24 { 25 return a.address < b.address; 26 } 27 int main() 28 { 29 int add, n, k; 30 cin >> add >> n >> k; 31 vector<Node> vec; 32 // input the data 33 for(int i=0; i<n; i++) 34 { 35 int inputa, inputb, inputc; 36 cin >> inputa >> inputb >> inputc; 37 Node node(inputa, inputb, inputc); 38 vec.push_back(node); 39 } 40 sort(vec.begin(), vec.end(), cmp); 41 Node* myList = new Node(); 42 int ncount = 0; 43 Node *p = NULL; 44 Node *q = NULL; 45 // deal the data from vector to list 46 vector<Node>::iterator it = vec.begin(); 47 while(1) 48 { 49 // find the first node 50 if(it->address == add) 51 { 52 if(myList->nextNode == NULL) 53 { 54 p = myList->nextNode = new Node(it->address, it->data, it->next); 55 } 56 else 57 { 58 p = p -> nextNode = new Node(it->address, it->data, it->next); 59 } 60 ncount ++; 61 if(it -> next == -1) 62 break; 63 else 64 add = it -> next; 65 } 66 it++; 67 if(it == vec.end()) 68 it = vec.begin(); 69 }// for 70 // if the k greater than effective data, then output all 71 if(k>ncount) 72 { 73 p = myList; 74 while(p->nextNode != NULL) 75 { 76 p = p -> nextNode; 77 if(p->next != -1) 78 printf("%.5d %d %.5d\n", p->address, p->data, p->next); 79 else 80 printf("%.5d %d -1\n", p->address, p->data); 81 } 82 }// if 83 else 84 { 85 Node *myNewList = new Node(); 86 // 借助栈来完成反转 87 stack<Node*> sta; 88 // 需要反转几次 89 int times = ncount/k; 90 // p始终指向MyList 91 p = myList; 92 // q始终指向MyNewList 93 q = myNewList; 94 // 进行times次反转 95 for(int j=0; j<times; j++) 96 { 97 for(int m=0; m<k; m++) 98 { 99 p = p -> nextNode; 100 sta.push(p); 101 } 102 for(int m=0; m<k; m++) 103 { 104 Node *qt = sta.top(); 105 sta.pop(); 106 if(myNewList->nextNode == NULL) 107 { 108 q = myNewList->nextNode = new Node(qt->address, qt->data, qt->next); 109 } 110 else 111 { 112 q = q -> nextNode = new Node(qt->address, qt->data, qt->next); 113 } 114 } 115 } // for 116 // 将剩下的节点依次插入到myNewList后面 117 while(p -> nextNode != NULL) 118 { 119 p = p -> nextNode; 120 if(myNewList->nextNode == NULL) 121 { 122 q = myNewList->nextNode = new Node(p->address, p->data, p->next); 123 } 124 else 125 { 126 q = q -> nextNode = new Node(p->address, p->data, p->next); 127 } 128 } // while 129 // 输出 130 p = myNewList; 131 while(p->nextNode != NULL) 132 { 133 p = p -> nextNode; 134 if (p->nextNode != NULL) 135 p->next = p->nextNode -> address; 136 else 137 p->next = -1; 138 if(p->next != -1) 139 printf("%.5d %d %.5d\n", p->address, p->data, p->next); 140 else 141 printf("%.5d %d -1\n", p->address, p->data); 142 } // while 143 }// else 144 return 0; 145 }
困扰我两周的难题终于解决了,试验了20多次将近30次,有图为证:
最后再粘一下AC的成果: