剑指offer---以O(1)时间删除链表节点
问题:删除链表节点
要求:以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 }
运行结果:
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); 所以应该是删除链表的第一个节点,可见结果正确。