20190331学习内容

一. 数据结构-链表
题目1:删除链表中重复的节点

代码实现:

public class DeleteDuplication {
     //原链表:0->1->1->2->3
    //处理后的链表:0->2->3
    public ListNode deleteDuplication(ListNode pHead) {
        if (pHead == null)
            return null;
        //方法1:使用HashMap实现---》写不下去了 //        int count = 0; //        Map<Object,Integer> map = new HashMap<>(); //        //将链表中节点的值塞进集合里面 //        ArrayList arrayList = new ArrayList(); // while (pHead != null){ //            arrayList.add(pHead.val); //    pHead = pHead.next; //        } //        //判断重复的节点 //        for (Object i : arrayList){ //            if (!map.containsKey(i)){ //   map.put(i,1); //            } //            else { //                map.put(i,map.get(i)+1); //                if () //            } //  }
        //保留pHead和first的初始值
        ListNode first = new ListNode(-1);
        first.next = pHead;
        ListNode p = pHead;

        //指向前一个节点
        ListNode preNode = first;

        //preNode->p->p.next
        while (p != null && p.next != null){
            //若当前节点数值与下一个节点数值相等
            if (p.val == p.next.val){
                int val = p.val;
                //继续向后查找
                while (p != null && p.val == val){
                    p = p.next;
                }
                //删除重复的节点
                preNode.next = p;
            }
            //如果当前节点数值与下一个节点数值不相等
            else {
                preNode = p;
                p = p.next;
            }
        }
        return first.next;
    }

    public static void main(String[] args) {
        //创建一个有重复节点的有序链表
        ListNode p1 = new ListNode(0);
        ListNode p2 = new ListNode(1);
        ListNode p3 = new ListNode(1);
        ListNode p4 = new ListNode(2);
        ListNode p5 = new ListNode(3);

        p1.next = p2;
        p2.next = p3;
        p3.next = p4;
        p4.next = p5;
        p5.next = null;
        
        DeleteDuplication d = new DeleteDuplication();
        ListNode result = d.deleteDuplication(p2);
        System.out.println("链表的第一个节点数值是:" + result.val);
        System.out.println("链表的第二个节点数值是:" + result.next.val); } }

//算法复杂度:O(n2)
//算法思路:定义一个节点指向头节点,从第一个节点开始遍历,若是重复节点,则删除重复节点,将头节点指向不重复节点

题目2. 找出链表中环的入口节点
代码实现:

public class EntryNodeOfLoop {
//    public ListNode entryNodeOfLoop(ListNode pHead) {
//        //方法1:使用HashSet实现,无序不能重复
//        if (pHead == null)
//            return null;
//
//        HashSet<ListNode> hashSet = new HashSet<>();
//        while (pHead != null){
//            //算法思路:从链表的第一个节点开始遍历,若某个元素出现次数超过一次,则输出
//            if (!hashSet.add(pHead)){
//                return pHead;
//            }
//            pHead = pHead.next;
//        }
//        return null;
//    }
    public ListNode entryNodeOfLoop(ListNode pHead) {
        if (pHead == null)
            return null;
        //方法2:计算循环
        ListNode fast = pHead;
        ListNode slow = pHead;
        while (fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
            //当快指针和慢指针相遇时
            if (fast == slow){
                fast = pHead;
                //再次相遇
                while (fast != slow){
                    fast = fast.next;
                    slow = slow.next;
                }
                if (fast == slow){
                    return slow;
                }
            }
        }
        return null;
    }
    public static void main(String[] args){
        //创建一个链表
        ListNode p1 = new ListNode(0);
        ListNode p2 = new ListNode(1);
        ListNode p3 = new ListNode(2);
        ListNode p4 = new ListNode(3);
        ListNode p5 = new ListNode(4);
        ListNode p6 = new ListNode(5);

        p1.next = p2;
        p2.next = p3;
        p3.next = p4;
        p4.next = p5;
        p5.next = p6;
        p6.next = p4;

        EntryNodeOfLoop en = new EntryNodeOfLoop();
        ListNode result = en.entryNodeOfLoop(p1);
        System.out.println(result.val);
    }
}

//方法1:空间复杂度:占用内存:9460k;时间复杂度:O(n)
//方法2:怎么实现的?https://www.cnblogs.com/fankongkong/p/7007869.html 空间复杂度:9408k,时间复杂度:?

二. 线程的创建和启动
第一种方法:

/**
 * @Author: qw
 * @Date: 2019/3/31
 * @Description:**继承Thread类创建线程类**
 */
public class FirstThread extends Thread{
    private int i;
    //第一步:重写run方法,run方法的方法体就是线程执行体
    public void run(){
        for ( ; i < 100; i++){
            //获取当前线程的名字
            System.out.println(this.getName() + "" + i);
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++){
            System.out.println(Thread.currentThread().getName() + "" + i);
            if (i == 20){
                //第二、三步:创建并启动第一个线程
                new FirstThread().start();
                //创建并启动第二个线程
                new FirstThread().start();
            }
        }
    }
}

第二种方法

/**
 * @Author: qw
 * @Date: 2019/3/31
 * @Description:**实现Runnable接口创建线程类**
 */
public class SecondThread implements Runnable{
    private int i;
    //第一步:重写Runnable接口的run()方法
    public void run(){
        for ( ; i < 100; i++){
            System.out.println(Thread.currentThread().getName() + "" + i);
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++){
            System.out.println(Thread.currentThread().getName() + "" + i);
            if (i == 20){
                //第二步:创建Runnable对象
                SecondThread st = new SecondThread();
                //第三步:将Runnable对象作为实参target创建线程对象
                new Thread(st,"新线程1").start();
                new Thread(st,"新线程2").start();
            }
        }
    }
}

第三种方法
/**

  • @Author: qw

  • @Date: 2019/3/31

  • @Description:使用Callable和Future创建线程
    */

    public class ThirdThread {
    public static void main(String[] args) {
    ThirdThread rt = new ThirdThread();
    //第一步:使用Lambda表达式创建一个Callable对象,然后将该实例包装成一个FutureTask对象,作为创建线程对象的实参传入
    FutureTask task = new FutureTask((Callable)()->{
    int i = 0;
    for ( ; i < 100; i++){
    System.out.println(Thread.currentThread().getName() + “的循环变量i的值:” + i);
    }
    return i;
    });

         for (int i = 0; i < 100; i++){
             System.out.println(Thread.currentThread().getName() + "循环变量i的值:" + i);
             if (i == 20){
                 //第二步:创建线程的对象并启动
                 new Thread(task,"有返回的线程").start();
             }
         }
         try {
             //获取线程返回值
             System.out.println("子线程的返回值:" + task.get());
         }
         catch (Exception ex){
             ex.printStackTrace();
         }
     } }
    

小结:三种方法的优缺点:
第一种方法:
优点:编程稍微简洁
缺点:1. 线程类不能继承其他类;2. 多个线程间不能共享实现类FirstThread的实例变量
第二、三种方法:
优点:1. 线程类可继承其他类;2. 多个线程间共享target对象,将CPU、代码和数据分开,体现了面向对象的思想。
缺点:编程稍微复杂

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值