链表操作对于我来说是一个相对薄弱的环节,需要好好练习。
一、删除链表中的节点
删除指定节点这种题目是链表的基本操作,本题题目如下:
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
现有一个链表 -- head = [4,5,1,9],它可以表示为:
4 -> 5 -> 1 -> 9
示例 1:
输入: head = [4,5,1,9], node = 5 输出: [4,1,9] 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
示例 2:
输入: head = [4,5,1,9], node = 1 输出: [4,5,9] 解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
说明:
- 链表至少包含两个节点。
- 链表中所有节点的值都是唯一的。
- 给定的节点为非末尾节点并且一定是链表中的一个有效节点。
- 不要从你的函数中返回任何结果。
思路:看到题目时首先需要找到该指定节点,也就是遍历找到该节点。其次,考虑找到之后的操作,因为要求是不要返回任何结果,所以直接修改即可,代码如下:其中传入的参数是需要删除的那个节点的指针。
void deleteNode(ListNode* node) {
node->val = node->next->val;
node->next = node->next->next;
}
二、删除链表的倒数第N个节点
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2. 当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
解题思路:我的最初想法是首先遍历一遍找到链表中一共有多少个节点,再根据N很容易得出是哪个节点需要删除。但是看到题目中要求是一遍扫描实现,这样的话就需要换个思路。
我们需要两个指针,第一个指针指向链表的头部,第二个指针指向第N个节点,两个节点同时向后遍历,直到第二个节点指向链表的尾部时,第一个节点就指向了链表的倒数第N个节点,这就巧妙地找到了指定节点。接下来再进行删除操作即可:
代码如下:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* first=head;
while(n--!=0)
first=first->next;
if(!first)
return head->next;
ListNode* sec=head;
while(first->next!=NULL){
sec=sec->next;
first=first->next;
}
sec->next=sec->next->next;
return head;
}
需要注意的是若需要删除的节点是头结点的话我们只需要将链表的头部向后移动一位即可。
三、
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
思路:由于自己对链表的不熟悉,看到这个题目时并没有想到很好的办法。只能百度参考了其他人的答案。
假设我们对V进行反转操作,那么本来V指向W,则反转之后V指向U,这时W就无法再访问到了,也就是产生了断链现象,为了避免断链,我们需要在指针转向之前先将下一个节点保存下来。因此我们需要三个节点来进行操作,代码如下:
ListNode* ReverseList(ListNode* pHead)
{
ListNode* pReversedHead = NULL;
ListNode* pNode = pHead;
ListNode* pPrev = NULL;
while(pNode != NULL)
{
ListNode* pNext = pNode->m_pNext;
if(pNext == NULL)
pReversedHead = pNode;
pNode->m_pNext = pPrev;
pPrev = pNode;
pNode = pNext;
}
return pReversedHead;
}
以上代码都是参考其他网友的回答,还需要对链表认真理解和学习。