链表
一、单向链表
假设单向链表的节点定义如下:
1 struct ListNode { 2 int val; 3 ListNode *next; 4 };
1、往链表结尾添加一个节点:
1 void AddToTail(ListNode **pHead, int value) { 2 ListNode *pNew = new ListNode(); 3 pNew->val = value; 4 pNew->next = NULL; 5 6 if (*pHead == NULL) { 7 *pHead = pNew; 8 } else { 9 ListNode *pNode = *pHead; 10 while (pNode->next != NULL) { 11 pNode = pNode->next; 12 } 13 pNode->next = pNew; 14 } 15 }
关键在于函数的第一个传入参数是一个指向指针的指针。当我们往空链表插入节点时,新插入的节点就是链表的头指针,由于此时会改动头指针,因此必须把pHead参数设置为指向指针的指针,否则出了这个函数pHead仍然是一个空指针。
如下面的代码:
1 void AddToTail(ListNode* pHead, int value) { 2 ListNode *pNew = new ListNode(); 3 pNew->val = value; 4 pNew->next = NULL; 5 6 if (pHead == NULL) { 7 pHead = pNew; 8 } else { 9 ListNode *pNode = pHead; 10 while (pNode->next != NULL) { 11 pNode = pNode->next; 12 } 13 pNode->next = pNew; 14 } 15 }
如果一开始是一个空链表,经过插入新节点后,虽然这个函数内部pHead指向新的节点,但是返回的链表,pHead还是空指针。
除了用指向指针的指针,还可以用引用(&):
1 void AddToTail(ListNode* &pHead, int value) { 2 ListNode *pNew = new ListNode(); 3 pNew->val = value; 4 pNew->next = NULL; 5 6 if (pHead == NULL) { 7 pHead = pNew; 8 } else { 9 ListNode *pNode = pHead; 10 while (pNode->next != NULL) { 11 pNode = pNode->next; 12 } 13 pNode->next = pNew; 14 } 15 }
2、在链表中找到第一个含有某值的节点,并删除该节点。
1 void RemoveNode(ListNode* &pHead, int value) { 2 if (pHead == nullptr) { 3 return; 4 } 5 ListNode *pToBeDelete = nullptr; 6 if (pHead->val == value) { 7 pToBeDelete = pHead; 8 pHead = pHead->next; 9 } else { 10 ListNode *pNode = pHead; 11 while (pNode->next != nullptr && pNode->next->val != value) { 12 pNode = pNode->next; 13 } 14 if (pNode->next != nullptr && pNode->next->val == value) { 15 pToBeDelete = pNode->next; 16 pNode->next = pNode->next->next; 17 } 18 } 19 if (pToBeDelete != nullptr) { 20 delete pToBeDelete; //只删除了pToBeDelete指针指向的对象,释放了它的堆内存空间,指针还是指向原来的内存 21 pToBeDelete = nullptr; //变成空指针,否则由于上面的delete操作,会使它变成野指针。 22 } 23 }
越努力,越幸运