删除单链表的倒数第m个元素

转载 2006年05月21日 09:08:00

[题目]:    给定一个单向链表(长度未知),请设计一个既节省时间又节省空间的算法来找出该链表中的倒数第m个元素。实现这个算法,并为可能出现的特例情况安排好处理措施。“倒数第m个元素”是这样规定的:当m=0时,链表的最后一个元素将被返回。
   
    如果沿从头至尾的方向从链表中的某个元素开始,遍历m个元素后刚好达到链表尾,那么该元素就是我们所要找的。这样,我们可以引出第一种办法:从头结点开始,依次对链表的每一个元素进行这样的测试,遍历m个元素,看是否到达链表尾。直到我们找到那个倒数第m个元素为止。很明显,这个方案的效率是很差的,因为我们将对同一批元素进行反复多次的遍历。仔细研究一下这个方案就会发现,对于链表中的大部分元素,我们都要遍历m个元素;如果这个链表的长度为n,这个算法的执行时间大概是O(mn)级的。我们应该尝试寻找一个优于O(mn)级的解决方案。


    如果我们首先遍历该链表,统计链表的长度(假定为n),那么要找的元素在该链表中的位置即n-m。这样,从链表的头开始,向后遍历n-m个元素即可。虽说整个过程需要对链表进行2次遍历,但它仍然是一个O(n)级的算法,而且它只需要很少的几个临时变量。相对于此前的方案,这一思路的时间和空间效率有了显著的改进。要是你能设法省下统计链表长度的那一次遍历,这个算法将更加有效了。


    首先不妨假设在前2种算法中我们用指针p1遍历链表。p1指向链表尾的时候,我们所要找的元素(假定为data-m)跟链表尾的相对距离为m。如果这时候有另外一个指针p2指向data-m,也就是说,p1与p2间隔m个元素。如果把该单向链表改为双向链表,并保持p1、p2之间的同步,当p2指针回溯到链表头结点的时候,p1指针刚好指向从头结点开始的第m个元素。根据这个相隔m个位置的相对距离,我们完全可以明确地再设置一个用来遍历单向链表的指针p2,让它与链表的第一个指针p1(前2种算法中用于统计链表长度的指针)间隔m个元素,然后让它们同步前进。当p1指向链表尾时,p2刚好指向倒数第m个元素。
    那么怎样才能让这2个指针保持正确的m间距呢?我们可以这样做:当p1从链表头开始统计链表元素个数(注意要从0开始计算),等数到第m个元素时,再让p2指针从链表头开始出发。这个,他们之间的距离就是m个元素了。
    在这一过程中,如果链表的长度不足m个元素,我们在试图使p1前进m个元素时,很可能就会在半路上遇见对“NULL”指针进行操作的情况。因此,我们需要在这2个指针的出发阶段检查p1指针是否已经到达了链表的尾端。

算法描述: element *FindMToLastElement (int head,int m)
                      {
                          element *p1,*p2;
                          int i;
                          p1 = head;
                          for(i=0;i<m;i++)
                              { 
                               if(p1->next)
                               p1 = p1->next;
                              else
                              return NULL;
                              }
                         p2 = head;
                         while(p1->next)
                           {
                            p1 = p1->next;
                            p2 = p2->next;
                           }
                        return p2;
                      }

            
C++实现:

/*show_MToLast_node.cpp     Amirural设计 */
#include <iostream.h>

class ListNode
{
private:
 int data;
 ListNode *next_node;
 static ListNode *now;                                                 //目前的结尾结点指针
 const static ListNode *head;                                    //连接链表的起始指针,head ->next_node指向第一个结点

public:
 ListNode(int node_data):data(node_data),next_node(NULL){}
 ListNode():next_node(NULL)
 {head=now=this;}
 static void add_node(int new_data);                      //增加新的结点
 static void show_all_node();                                   //显示所有的结点          
 static void show_MToLast_node(int m);              //显示倒数第m个结点
};

ListNode *ListNode::now;           
const ListNode *ListNode::head;

void ListNode::add_node(int new_data)
{
 now->next_node=new ListNode(new_data);
 now=now->next_node;
}

void ListNode::show_all_node()
{
 now=head->next_node;
 while(now!=NULL)
 {
 cout<<now->data;
 if(now->next_node!=NULL)
  cout<<"->";
 now=now->next_node;
 }
}

void ListNode::show_MToLast_node(int m)
{
        ListNode *index,*mBehind;
        int i;
        index = head->next_node;
        for(i=0;i<m;i++)
         { 
         if(index->next_node)
          index = index->next_node;
        }

        mBehind = head->next_node;
        while(index->next_node)
        {
          index = index->next_node;
          mBehind = mBehind->next_node;
        }
        cout<<"The m to last data is:"<<mBehind->data<<endl;
 }

void main()
{
 int data,m;
 char choice;
 ListNode startnode;               

 do{
  cout<<"Please input data:";
  cin>>data;

  startnode.add_node(data);  
       
  cout<<"Do you want to input another data?";
  cin>>choice;
 }while(choice=='y'||choice=='Y');

 ListNode::show_all_node();

 cout<<"/nPlease input m:";
 cin>>m;
 ListNode::show_MToLast_node(m);
}

查找单链表倒数第k个元素

查找单链表倒数第m个结点,要求时间复杂度为O(n).(提示,使用双指针) 解题思路: 常规思路为先获取链表的长度N,然后返回N-k+1位置处的结点即可。但是中需要遍历两次链表。 我们使用另一种算法...
  • undersky_chen
  • undersky_chen
  • 2016年02月23日 13:38
  • 639

单链表操作之删除倒数第k个结点

****单链表操作之删除倒数第k个结点**** //函数功能:删除链表的倒数第k个结点;1 //自定义的结点结构体和头指针结构体: //函数原型:void DelKNode(pLin...
  • bitboss
  • bitboss
  • 2016年06月10日 18:28
  • 1626

笔试题&面试题:设计一个复杂度为n的算法找到单向链表倒数第m个元素

设计一个复杂度为n的算法找到单向链表倒数第m个元素.最后一个元素假定是倒数第0个. 提示:双指针查找 相对于双向链表来说,单向链表只能从头到尾依次访问链表的各个节点,所以如果要找链表的倒数第m个元...
  • laoniu_c
  • laoniu_c
  • 2014年08月10日 11:43
  • 1579

[算法]找出单链表中的倒数第k个元素

找出单链表中的倒数第k个元素解题思路: 为了求出链表中的倒数第k个元素,最容易想到的方法是首先遍历一遍单链表,求出整个单链表的长度n,然后将倒数第k个,转换为正数第n-k个,接下去遍历一次就可以得...
  • CodeEmperor
  • CodeEmperor
  • 2016年05月06日 16:12
  • 3104

如何找出单链表中的倒数第k个元素

如何找出单链表中的倒数第k个元素
  • jsqfengbao
  • jsqfengbao
  • 2015年04月04日 20:39
  • 3272

求链表的倒数第m个元素

习题3.5 求链表的倒数第m个元素   (20分) 请设计时间和空间上都尽可能高效的算法,在不改变链表的前提下,求链式存储的线性表的倒数第m(>0>0)个元素。 函数接口定义: El...
  • u013243314
  • u013243314
  • 2017年06月23日 10:47
  • 920

LintCode 找到单链表倒数第n个节点

给出链表 3->2->1->5->null和n = 2,返回倒数第二个节点的值1. 设置2个指针,当第一个指针从表头向前走到第n-1个节点时,第二个指针开始从表头出发。当第一个指针走到尾节点时,...
  • sinat_30440627
  • sinat_30440627
  • 2016年03月27日 19:59
  • 817

Java - 删除链表中倒数第n个节点

给定一个链表,删除链表中倒数第n个节点,返回链表的头节点。  注意事项 链表中的节点个数大于等于n 您在真实的面试中是否遇到过这个题?  Y...
  • wzhworld
  • wzhworld
  • 2017年08月08日 11:10
  • 151

【华为oj】输出单向链表中倒数第k个结点

问题描述:          输入一个单向链表,输出该链表中倒数第k个结点,链表的倒数第0个结点为链表的尾指针。 链表结点定义如下: struct ListNode {      int  ...
  • haoxiaodao
  • haoxiaodao
  • 2015年08月09日 17:51
  • 779

输出单链表中倒数第k个结点(Java版)

题目:输入带头结点的单链表L,输出该单链表中倒数第k个结点。单链表的倒数第0个结点为该单链表的尾指针。要求只能遍历一次单链表。 解题思路: 如果不要求只能遍历一次单链表,我们可以先...
  • lavor_zl
  • lavor_zl
  • 2015年01月17日 15:40
  • 1482
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:删除单链表的倒数第m个元素
举报原因:
原因补充:

(最多只允许输入30个字)