[算法]Java实现 不断前移重复出现的元素 Move Element To Front

来源:互联网 发布:windows mirai病毒 编辑:程序博客网 时间:2024/06/07 02:27

不断前移重复出现的元素 Move Element To Front

关键词

链表 Java 前移元素 删除

算法过程

  1. 使用链表存储数据,依次读取单个元素;
  2. 当前输入元素与先前输入的元素存在重复时,先删除链表中的结点;
  3. 于链表表头插入元素;

完整源码

/*          JavaCode  重复元素前移*/// ---- 测试用例 ---- public class TestMove2Front{    public static void main(String args[]){        MoveToFront m;        m = new MoveToFront();        int[] a = {4,3,2,2,1,2,0,1,2};        System.out.println("Push code \n" +                "Top same: 0,First time: 1;Aagin: 2\n");        for(int i=0;i<a.length;i++){            int code = m.checkDup(a[i]);            System.out.println("Input a[i]: "+a[i]+" ; Push code : "+code+"\n");            if(code>0)            m.push(a[i],code);        }        while(!m.isEmpty())            System.out.println("Out: "+m.pop());    }}// ---- 实现类 ----class MoveToFront{       private Node first;    private int N;    // 循环类实现链表结构    public class Node{        int item;        Node next;    }    // 判断链表是否为空    public boolean isEmpty(){        return first == null;     }     public MoveToFront(){    }    // 弹出表头元素    public int pop(){        int item = first.item;        first = first.next;        return item;        }    // 表头插入元素    public void push(int item){            Node oldfirst = first;            first = new Node();            first.item = item;            first.next = oldfirst;    }    // 判断元素是否重复,返回状态代码    /*     code :0 相同元素连续输入,即:当前输入元素与表头一致;     code : 1 不存在重复元素,不进行结点删除操作;     code : 2 存在重复元素,进行结点删除操作;    */    public int checkDup(int item){        int code = 0;        Node current = first;        boolean again = false;        int step = 0; //记录从表头开始计数达到重复结点需要走的步数        while(current!=null){            if(current.item == item){                again = true; // 值为真,说明存在重复结点                break;            }            current = current.next;            step++;        }        if(!again) code = 1;         else{ // 对重复结点进行删除             if(item == first.item) code = 0; //代表重复元素连续输入            else{            System.out.println("Duplicate step : "+step); //输入要前进的步数用于测试观察                current = first;                for(int i=0;i<(step-1);i++)//找到要被删除的结点的前一结点                    current = current.next;                // 进行结点删除操作                current.next = current.next.next;                code = 2;            }        }        return code;    }}

输出结果

Push code Top same: 0,First time: 1;Aagin: 2Input a[i]: 4 ; Push code : 1Input a[i]: 3 ; Push code : 1Input a[i]: 2 ; Push code : 1Input a[i]: 2 ; Push code : 0Input a[i]: 1 ; Push code : 1Duplicate step : 1Input a[i]: 2 ; Push code : 2Input a[i]: 0 ; Push code : 1Duplicate step : 2Input a[i]: 1 ; Push code : 2Duplicate step : 2Input a[i]: 2 ; Push code : 2Out: 2Out: 1Out: 0Out: 3Out: 4

代码心得

用例代码能做到以下3件事:

  1. 针对当前输入元素,判断是否存在重复元素,并返回对应的状态码int checkDup(int item)
  2. 针对返回的状态吗,选择要进行相关的链表操作if(code>0){...} ;
  3. 发送进行链表操作的指令push(int item)

实现类,就是上述操作的具体实现,尽量做到了DO WAHT 以及HOW TO DO 的各司其职;

调试代码的过程中遭遇了两次 NullPointerException

1、计数

最初的实现类中,使用了一个int N来记录结点数判断链表是否为空,删除重复结点时,忘记把计数减一了,导致用例代码中遍历到了一个NullPointerException。解决方案: 直接判断表头结点是否为NULL来判断链表是否为空;

public boolean isEmpty(){        return first == null;     } 

2、 删除

一开始完全顾着写存在重复的情况,没有先进行预判,结果在删除结点的时候,单单一句 current.next = current.next.next; 就会报空指针。

BUG比较曲折:后来开断点调试发现是因为在最初的糟糕设计里,那些不存在重复元素的情况下, 按照代码其实步数step会一直走到尾结点,那样的话尾结点的next已然是null了,怎么可以给null赋值,后来是把代码整体全部改了之后,也就是先预判了存在重复的情况才可以进行删除操作;

下面这段历史代码还是很有趣的,因为我觉得它其实看上去根本就是废话,但是在不进行预判的时候(也就是不判断是不是存在重复的时候,奇迹般地起效了…)要对链表进行删除操作真的要非常小心,删头删尾删中间都不一样:

if(current.next != null){                        current.next = current.next.next;                    }                else{                    current.next = null;                }

应用即最常用的数值永远位于前部

0 0
原创粉丝点击