常见的链表操作

1. 单链表的逆序

包括逆序输出链表,三种方式,第一种是操作用栈的方式,将链表装入栈中,然后新建链表进行输出;第二种是头结点插入,没来一个节点,就插入头结点之后;第三种是对称交换,将链表以中心节点为中心,进行对称交换。

2. 合并有序链表

有序链表合并是有两种方式,一种是新建一个全新的链表,对比两个有序的链表的对应节点的大小,一次添加到新建的链表中,如果两个链表不等长,那么最后将长的那一个追加到新建链表的结尾;第二种方式与第一种方式相似,但是这种方式不新建链表,只是修改原链表的指针来进行修改,其他的与第一种方式一样

3. 判断两个单链表是否交叉,如果交叉,返回第一个交叉的节点

单链表的交叉情况,最后肯定是一个Y型的链表,也就是说,链表最后肯定是有一个公共的部分(至少为一个节点)。首先判断两个单链表的是否交叉,就是对两个链表进行遍历,看遍历的最后的节点是否相等,如果相等,那么就是交叉链表;第二步 ,就是找出第一个相交的节点,这个过程可以有两种方式:1、用长的链表减去abs(长链表-短链表),然后从短链表的头开始,从长链表的减去的对应位置开始进行链表元素的遍历比较,第一个相等的元素就是交叉链表的交点;2、将两个链表的元素全部放入两个栈中,然后比较出栈,这是相当于从链表的尾部来依次遍历两个链表,找到第一个不相等的元素,那么这个元素的前一个元素就是他们的交点;

4. 判断单链表是否有环, 如果有环则返回进入环的第一个结点

判断链表是否有环,可以设置快慢指针,例如设置指针a,b,a前进一步,b前进两部,如果b最后的元素为null,那么证明没有环,如果a==b,那么证明链表中是有环的。

如何返回第一个进入环的节点?将结点的地址做hash,遍历链表,检测是否有地址相等的结点。还有一种方式是,采用java中是set或者是hashMap结构,当第一个使该结构长度不在增加的元素出现的时候,这个元素就是进入环的第一个节点。

5. 找出单链表的中间的元素

设置快慢指针,快指针向前走两个位置,慢指针向前走一个位置,当快指针走到链表尾部的时候,慢指针正好在链表的中间;

6. 删除单链表中倒数第K个元素

设置两个指针p1和p2,p1指向链表第一个结点,p2指向第k+1个结点,两个指针同时前进,当p2到达链表尾时,p1指向倒数第k+1个结点,删除p1后面的一个结点即可。

7. 在单链表的指定节点前插入一个节点

复制一个当前节点,那么链表中现在有两个相同的相连的节点,然后用插入节点覆盖前一个节点,实现插入

8. 约瑟夫环

从题目要求中我们无法直观的感知该问题,得从一个测试用例开始。
假设0,1,2,3,4这5个数字组成一个圆圈,如果我们从数字0开始每次删除第3个数字,则删除的前四个数字是2,0,4,1,3。
这就是有名的约瑟夫环问题,它有一个简洁的数学公式,但除非我们有很深的数学素养和数学灵敏性,否则是很难一下子想出来的。
程序员最普遍的方法就是想尽一切办法让我们的代码通过测试用例。
既然是一个圆圈,我们自然就会联想到环形链表:

int LastRemaining(unsigned int n, unsigned int m)
{
    if(n < 1 || m < 1)
    {
         return -1;
    }

    unsigned int i = 0;

    lisg<int> numbers;
    for(i = 0; i < n; ++i)
    {
         numbers.push_back(i);
    }

    list<int> :: iterator current = numbers.begin();
    while(numbers.size() > 1)
    {
        for(int i = 1l i < m; ++i)
        {
              current++;
              if(current == numbers.end()){
                    current = number.begin();
              }
         }

         list<int> :: iterator next = ++current;
         if(next == numbers.end()){
               next = numbers.begin();
         }

         --current;
         numbers.erase(current);
         current = next;
    }

    return *(current);
}
  我们可以用std :: list来模拟一个环形链表,但因为std :: list本身并不是一个环形结构,所以我们还要在迭代器扫描到链表末尾的时候,把迭代器移到链表的头部。 

 如果是使用数学公式的话,代码就会非常简单:
int LastRemaining(unsigend int n, unsigned int m)
{
    if(n < 1 || m < 1)
    {
          return -1;
    }

    int last = 0;
    for(int i = 2; i <= n; ++i)
   {
       last = (last + m) % i;
   }

   return last;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值