zoukankan      html  css  js  c++  java
  • 剑指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 }
    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); 所以应该是删除链表的第一个节点,可见结果正确。

  • 相关阅读:
    关于数组的练习题:
    函数(手写)
    常用函数和方法集
    用户输入年,月,日,计算该日是该年的第几天?需要考虑2月份的问题
    [备用] 你会在C#的类库中添加web service引用吗?
    [备用]权限设计方案、如何使用session、MVC如何使用模板、DropdownList、怎么添加Bootstrape框架、使用ASP.NET MVC 4 Bootstrap Layout Template(VS2012)
    [转:Pro ASP.NET MVC 5中的例子]使用MVC4,Ninject,EF,Moq,构建一个真实的应用电子商务SportsStore
    莫名其妙
    [备用] VS中生成报表
    [备用] 百度地图兴趣点抓取
  • 原文地址:https://www.cnblogs.com/iwangzhengchao/p/9775687.html
Copyright © 2011-2022 走看看