简单链表
参考:http://zhedahht.blog.163.com/
- 输入一个链表的头结点,从尾到头反过来打印出每个节点的值。
- 给定单向链表的头结点和一个结点指针,定义一个函数在O(1)时间删除该结点。
- 输入一个单链表的,输出该链表中倒数第k个结点。
- 定义一个函数,输入一个链表的头结点,反转该链表并输出反转链表的头结点。
1、思路:
递归方式:利用栈的“先入后出”的特性,轻松解决。这里提供一个递归方法来模拟栈。
PrintListReverse
1 void PrintListReverse(ListNode* head) 2 { 3 if (head != NULL) 4 { 5 PrintListReverse(head->pNext); 6 printf("%d\t", head->nValue); 7 } 8 }
非递归方式:直接利用栈。
1 void PrintReverseIter(ListNode* pHead) 2 { 3 std::stack<ListNode*> nodes; 4 ListNode* pNode = pHead; 5 while (pNode != NULL) 6 { 7 nodes.push(pNode); 8 pNode = pNode->m_pNext; 9 } 10 11 while (!nodes.empty()) 12 { 13 pNode = nodes.top(); 14 printf("%d\t", pNode->m_nValue); 15 nodes.pop(); 16 } 17 printf("\n"); 18 }
2、思路:
常用算法需要记录删除结点node的前一个结点pre,因为需要把node的后一个结点next赋给pre->pNext,不让单链表断裂,这样就需要从头遍历链表,时间复杂度为O(n)。换个角度,将next的内容覆盖node,删除next结点,这样假象删除node。涉及到node->pNext->pNext,所以需要分情况讨论,看是删除的是尾结点,如果是尾结点,就没有node->pNext->pNext,只能从头遍历链表。
DeleteNode
1 void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted) 2 { 3 if(!pListHead || !pToBeDeleted) 4 return; 5 6 // 要删除的结点不是尾结点 7 if(pToBeDeleted->m_pNext != NULL) 8 { 9 ListNode* pNext = pToBeDeleted->m_pNext; 10 pToBeDeleted->m_nValue = pNext->m_nValue; 11 pToBeDeleted->m_pNext = pNext->m_pNext; 12 13 delete pNext; 14 pNext = NULL; 15 } 16 // 链表只有一个结点,删除头结点(也是尾结点) 17 else if(*pListHead == pToBeDeleted) 18 { 19 delete pToBeDeleted; 20 pToBeDeleted = NULL; 21 *pListHead = NULL; 22 } 23 // 链表中有多个结点,删除尾结点 24 else 25 { 26 ListNode* pNode = *pListHead; 27 while(pNode->m_pNext != pToBeDeleted) 28 { 29 pNode = pNode->m_pNext; 30 } 31 32 pNode->m_pNext = NULL; 33 delete pToBeDeleted; 34 pToBeDeleted = NULL; 35 } 36 }
3、思路:
设置两个指针,相隔k-1个,这样后指针到达结尾,那么前指针就到达了前k个结点。注意,要保证链表长度超过k个,在预处理后指针时要做出判断。
FindKthToTail
1 ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) 2 { 3 if(pListHead == NULL || k == 0) 4 return NULL; 5 6 ListNode *pAhead = pListHead; 7 ListNode *pBehind = NULL; 8 9 for(unsigned int i = 0; i < k - 1; ++ i) 10 { 11 if(pAhead->m_pNext != NULL) 12 pAhead = pAhead->m_pNext; 13 else 14 { 15 return NULL; 16 } 17 } 18 19 pBehind = pListHead; 20 while(pAhead->m_pNext != NULL) 21 { 22 pAhead = pAhead->m_pNext; 23 pBehind = pBehind->m_pNext; 24 } 25 26 return pBehind; 27 }
4、思路:
递归方式:有点难理解。
1 ListNode* ReverseRecursive(ListNode* head) 2 { 3 if (head == NULL || head->m_pNext == NULL) 4 return head; 5 ListNode *curr, *next, *tail; 6 curr = head; 7 next = head->m_pNext; 8 9 tail = ReverseRecursive(next); 10 11 next->m_pNext = curr; 12 curr->m_pNext = NULL; 13 return tail; 14 }
非递归方式:留意结点移动的界限,移动到尾结点停止。
ReverseList
1 ListNode* ReverseList(ListNode* pHead) 2 { 3 ListNode* pReversedHead = NULL; 4 ListNode* pNode = pHead; 5 ListNode* pPrev = NULL; 6 while(pNode != NULL) 7 { 8 ListNode* pNext = pNode->m_pNext; 9 10 if(pNext == NULL) 11 pReversedHead = pNode; 12 13 pNode->m_pNext = pPrev; 14 15 pPrev = pNode; 16 pNode = pNext; 17 } 18 19 return pReversedHead; 20 }