链表笔试面试题

  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 }

 

posted @ 2016-09-20 17:20  Ricardo  阅读(489)  评论(0编辑  收藏  举报