剑指offer---以O时间删除链表节点

Posted iwangzhengchao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指offer---以O时间删除链表节点相关的知识,希望对你有一定的参考价值。

问题:删除链表节点

要求:以O(1)时间

对于删除指定索引的链表元素大家都很熟悉,思路一般是从头遍历链表直到指定索引位置删除元素,然后维护一下指针即可,时间复杂度O(n)。代码如下:

 1 // 删除position位置的数据,并返回
 2 int List::erasePosition(int position){
 3     if(position<0 || position>(List::size()-1)){
 4         cout<<"position error, please check."<<endl;
 5         return -1;
 6     }
 7     int res = List::getValue(position);
 8     Node *p = head;
 9     int index = 0;
10     cout<<"erase data at position "<<position<<endl;
11     if(position == 0){
12         head = p->next;
13         return res;
14     }
15     else{
16         while(index != position-1){
17             p = p->next;
18             index++;
19         }
20         Node *temp = p->next;
21         p->next = temp->next;
22         return res;
23     }
24 }

上述代码的完整版在这里

但是当删除指定地址的链表元素时,事情变得不太一样了,在这种情况下我们可以实现O(1)时间删除指定地址的数据。当然,以上是基于一个假设:要删除的节点一定在链表里面。

技术分享图片

如上图所示,我们打算删除节点e,可以将节点e的后一个节点b的内容复制到节点e,即覆盖原有内容,然后删除后一个节点b。(这里我感觉待删除地址还是有节点的,只是内容变了,与直接删除节点e有相似的效果)

注意点:空指针与尾节点的情况(详见代码)

解题代码:

 1 void List::erase(Node *pDelete){
 2     if (pDelete == nullptr)
 3         return ;
 4     // 删除的的节点不是尾节点
 5     if(pDelete->next != nullptr){
 6         Node *pNext = pDelete->next;
 7         pDelete->data = pDelete->next->data;
 8         pDelete->next = pNext->next;
 9         delete pNext;
10         pNext = nullptr;
11     }
12     // 链表只有一个节点,删除第一个节点
13     else if(head == pDelete){
14         delete pDelete;
15         pDelete = nullptr;
16         head = nullptr;
17     }
18     // 链表中有多个节点,要删除尾节点
19     else{
20         Node *p = head;
21         while(p->next!= pDelete){
22             p = p->next;
23         }
24         p->next = nullptr;
25         delete pDelete;
26         pDelete = nullptr;
27     }
28 }

完整版代码:

技术分享图片
  1 #include<iostream>
  2 using namespace std;
  3 
  4 class Node {
  5 public:
  6     int data;
  7     Node *next;
  8     Node(int da):
  9         data(da), next(NULL){}
 10 };
 11 
 12 class List{
 13 public:
 14     Node *head;
 15     List(): head(NULL){}
 16     ~List(){
 17         delete head;
 18         cout<<"The list is deleted."<<endl;
 19     };
 20     int size();
 21     int getValue(int position);
 22     void printList(); // 打印链表
 23     void insert(int position, int value); // 指定位置插入
 24     void insertHead(int value); // 插入到最前
 25     void insertTail(int value); // 插入到最后
 26     int erasePosition(int position); // 删除指定位置的节点
 27     void erase(Node *pDelete);
 28 
 29 };
 30 
 31 // 返回position位置的数据
 32 int List::getValue(int position){
 33     if(position<0 || position>(List::size()-1)){
 34         cout<<"position error, please check."<<endl;
 35         return -1;
 36     }
 37     Node *p = head;
 38     int index = 0;
 39     while(index != position){
 40         p = p->next;
 41         index++;
 42     }
 43     //cout<<"position "<<position<<" is "<<p->data<<endl;
 44     return p->data;
 45 }
 46 
 47 // 返回链表大小
 48 int List::size(){
 49     Node *p = head;
 50     int index = 0;
 51     while(p != NULL){
 52         index++;
 53         p = p->next;
 54     }
 55     return index;
 56 }
 57 
 58 
 59 // 打印链表
 60 void List::printList(){
 61     Node *p = head;
 62     while(p != NULL){
 63         cout<<p->data<<" ";
 64         p = p->next;
 65     }
 66     cout<<endl;
 67     cout<<endl;
 68 }
 69 
 70 // 在position位置插入value
 71 void List::insert(int position, int value){
 72     if(position<0 || position>List::size()){
 73         cout<<"position error, please check."<<endl;
 74         return ;
 75     }
 76     Node *s = new Node(value); // new node
 77     Node *p = head;
 78     if(head == NULL){ // isEmpty = true
 79         head = s;
 80     }
 81     else{ // isEmpty = false
 82         if(position == 0){
 83             s->next = p;
 84             head = s;
 85         }
 86         else{
 87             int index = 0;
 88             while(index != position-1){
 89                 p = p->next;
 90                 index++;
 91             }
 92             s->next = p->next;
 93             p->next = s;
 94         }
 95     }
 96     if (position == 0)
 97         cout<<"insert "<<value<<" at the first."<<endl;
 98     else if (position == List::size())
 99         cout<<"insert "<<value<<" at the tail."<<endl;
100     else
101         cout<<"insert "<<value<<" at position "<<position<<endl;
102 }
103 
104 // 头部插入
105 void List::insertHead(int value){
106     List::insert(0, value);
107 }
108 
109 // 尾部插入
110 void List::insertTail(int value){
111     List::insert(List::size(), value);
112 }
113 
114 // 删除position位置的数据,并返回
115 int List::erasePosition(int position){
116     if(position<0 || position>(List::size()-1)){
117         cout<<"position error, please check."<<endl;
118         return -1;
119     }
120     int res = List::getValue(position);
121     Node *p = head;
122     int index = 0;
123     cout<<"erase data at position "<<position<<endl;
124     if(position == 0){
125         head = p->next;
126         return res;
127     }
128     else{
129         while(index != position-1){
130             p = p->next;
131             index++;
132         }
133         Node *temp = p->next;
134         p->next = temp->next;
135         return res;
136     }
137 }
138 
139 void List::erase(Node *pDelete){
140     cout<<"erase data at address "<<pDelete<<endl;
141     if (pDelete == nullptr)
142         return ;
143     // 删除的的节点不是尾节点
144     if(pDelete->next != nullptr){
145         Node *pNext = pDelete->next;
146         pDelete->data = pDelete->next->data;
147         pDelete->next = pNext->next;
148         delete pNext;
149         pNext = nullptr;
150     }
151     // 链表只有一个节点,删除第一个节点
152     else if(head == pDelete){
153         delete pDelete;
154         pDelete = nullptr;
155         head = nullptr;
156     }
157     // 链表中有多个节点,要删除尾节点
158     else{
159         Node *p = head;
160         while(p->next!= pDelete){
161             p = p->next;
162         }
163         p->next = nullptr;
164         delete pDelete;
165         pDelete = nullptr;
166     }
167 }
168 
169 int main() {
170     List l1;
171     l1.insertTail(6);
172     l1.insertHead(7);
173     l1.insert(1, 5);
174     l1.insert(0, 16);
175     l1.insert(2, 56);
176     l1.insert(0, 169);
177     l1.insert(6, 16);
178     cout<<endl<<"The list is:"<<endl;
179     l1.printList();
180     l1.erasePosition(0);l1.printList();
181     l1.erase(l1.head);l1.printList();
182     return 0;
183 }
View Code

运行结果:

 1 insert 6 at the first.
 2 insert 7 at the first.
 3 insert 5 at position 1
 4 insert 16 at the first.
 5 insert 56 at position 2
 6 insert 169 at the first.
 7 insert 16 at position 6
 8 
 9 The list is:
10 169 16 7 56 5 6 16 
11 
12 erase data at position 0
13 16 7 56 5 6 16 
14 
15 erase data at address 0x3b1a58
16 7 56 5 6 16 
17 
18 The list is deleted.
19 [Finished in 1.3s]

由于主函数传的是 l1.erase(l1.head); 所以应该是删除链表的第一个节点,可见结果正确。

以上是关于剑指offer---以O时间删除链表节点的主要内容,如果未能解决你的问题,请参考以下文章

剑指offer18删除链表的(重复)节点

剑指Offer之在O时间删除链表节点

剑指offer 面试18题

剑指Offer对答如流系列 - 在O时间删除链表结点

Java 剑指offer(17) 在O时间删除链表结点

《剑指Offer——在O时间删除链表结点,链表中倒数第k个结点》代码