链表笔试面试题
1 // 链表节点 2 struct ListNode 3 { 4 int value; 5 ListNode* next; 6 }; 7 8 // 求单链表中结点的个数 注意链表判断是否为空 时间复杂度O(n) 9 size_t GetListLength(ListNode* head) 10 { 11 if(!head) 12 { 13 return 0; 14 } 15 16 size_t length = 0; 17 ListNode* current = head; 18 19 while (current != NULL) 20 { 21 ++length; 22 current = current->next; 23 } 24 25 return length; 26 } 27 28 // 反转单链表 时间复杂度O(n) 29 ListNode* ReverseList(ListNode* head) 30 { 31 // 如果链表为空或只有一个结点,无需反转,直接返回原链表头指针 32 if(head == NULL && head->next == NULL) 33 { 34 return NULL; 35 } 36 37 ListNode* new_head = NULL; // 链表反转后新链表的头结点 38 ListNode* current = head; 39 40 while (current != NULL) 41 { 42 ListNode* tmp = current; // 保存当前结点 43 current = current->next; 44 tmp->next = new_head; // 插入到新的头结点之前 45 new_head = tmp; 46 } 47 48 return new_head; 49 } 50 51 // 查找单链表中倒数第K个数(k>0) 52 /*主要思路就是使用两个指针,先让前面的指针走到正向第k个结点,这样前后两个指针的距离差是k-1, 53 之后前后两个指针一起向前走,前面的指针走到最后一个结点时,后面指针所指结点就是倒数第k个结点。*/ 54 ListNode* GetReverseKthNode(ListNode* head, size_t k) 55 { 56 if(k == 0 || head == NULL) 57 { 58 return NULL; 59 } 60 61 ListNode* ahead = head; 62 ListNode* back = head; 63 64 65 while (k > 1 && ahead != NULL) // 前面的指针先走到正向第k个结点 66 { 67 ahead = ahead->next; 68 --k; 69 } 70 71 if(k > 1 || ahead == NULL) //结点数目小于k 返回NULL 72 { 73 return NULL; 74 } 75 76 while(ahead->next != NULL) // 前后两个指针一起向前走,直到前面的指针指向最后一个结点 77 { 78 back = back->next; 79 ahead = ahead->next; 80 } 81 82 return back; // 后面的指针所指结点就是倒数第k个结点 83 } 84 85 //查找单链表的中间结点 若链表长度为n(n>0),则返回第n/2+1个结点 86 //设置两个指针,只不过这里是,两个指针同时向前走,前面的指针每次走两步, 87 //后面的指针每次走一步,前面的指针走到最后一个结点时,后面的指针所指结点就是中间结点,即第(n/2+1)个结点。 88 //注意链表为空,链表结点个数为1和2的情况。时间复杂度O(n)。 89 ListNode* GetMiddleNode(ListNode* head) 90 { 91 if(head == NULL || head->next == NULL) // 链表为空或只有一个结点,返回头指针 92 { 93 return NULL; 94 } 95 96 ListNode* ahead = NULL; 97 ListNode* back = NULL; 98 99 while(ahead->next != NULL) // 前面指针每次走两步,直到指向最后一个结点,后面指针每次走一步 100 { 101 ahead = ahead->next; 102 back = back->next; 103 if(ahead->next != NULL) 104 { 105 ahead = ahead->next; 106 } 107 } 108 109 return back; 110 } 111 112 // 从尾到头打印单链表 113 // 对于这种颠倒顺序的问题,我们应该就会想到栈,后进先出。 114 void ReversePrintList(ListNode* head) 115 { 116 std::stack<ListNode*> stack; 117 ListNode* node = head; 118 119 while(node != NULL) 120 { 121 stack.push(node); 122 node = node->next; 123 } 124 125 while(!stack.empty()) 126 { 127 node = stack.top(); 128 cout << node->value; 129 stack.pop(); 130 } 131 } 132 133 // 从尾到头打印单链表递归版本 134 void ReversePrintList_recursion(ListNode* node) 135 { 136 if(node == NULL) 137 { 138 return; 139 } 140 else 141 { 142 ReversePrintList_recursion(node->next); 143 cout << node->value; 144 } 145 } 146 147 // 两个单链表Head1和Head2 各自有序,把它们合并成一个链表依然有序 148 // 注意两个链表都为空,和其中一个为空时的情况 149 ListNode* MergeSortedList(ListNode* head_1, ListNode* head_2) 150 { 151 if(head_1 == NULL) 152 { 153 return head_2; 154 } 155 if(head_2 == NULL) 156 { 157 return head_1; 158 } 159 160 ListNode* new_head = NULL; // 合并后新链表的头结点 161 162 /* 先让new_head指向head1和head2值小的那个 */ 163 if(head_1->value <= head_2->value) 164 { 165 new_head = head_1; 166 head_1 = head_1->next; 167 new_head->next = NULL; 168 } 169 else 170 { 171 new_head = head_2; 172 head_2 = head_2->next; 173 new_head->next = NULL; 174 } 175 176 /* 依次比较head1中head2中的值,哪个小就插入到新链表中 */ 177 ListNode* tmp = new_head; 178 while(head_1 != NULL && head_2 != NULL) 179 { 180 if(head_1->value <= head_2->value) 181 { 182 tmp->next = head_1; 183 head_1 = head_1->next; 184 tmp = tmp->next; 185 tmp->next = NULL; 186 } 187 else 188 { 189 tmp->next = head_2; 190 head_2 = head_2->next; 191 tmp = tmp->next; 192 tmp->next = NULL; 193 } 194 } 195 196 /* head1与head2中长的链表剩余的部分插入到新链表中 */ 197 if(head_1 != NULL) 198 { 199 tmp->next = head_1; 200 } 201 else if(head_2 != NULL) 202 { 203 tmp->next = head_2; 204 } 205 206 return new_head; 207 } 208 209 // 判断链表是否有环 210 // 如果一个链表中有环,也就是说用一个指针去遍历,是永远走不到头的。 211 // 因此,我们可以用两个指针去遍历,一个指针一次走两步,一个指针一次走一步,如果有环,两个指针肯定会在环中相遇。 212 // 时间复杂度为O(n) 213 bool hasCircle(ListNode* head) 214 { 215 ListNode* fast = head; 216 ListNode* slow = head; 217 218 while(fast != NULL && fast->next != NULL) 219 { 220 fast = fast->next->next; 221 slow = slow->next; 222 223 if(fast == slow) 224 { 225 return true; 226 } 227 } 228 229 return false; 230 }