数据结构与算法

Hailstone序列问题

这里写图片描述
3n+1问题是一个简单有趣而又没有解决的数学问题。这个问题是由Collatz在1937年提出的。克拉兹问题(Collatz problem)也被叫做hailstone问题、3n+1问题、Hasse算法问题、Kakutani算法问题、Thwaites猜想或者Ulam问题。
问题如下:
(1)输入一个正整数n;
(2)如果n=1则结束;
(3)如果n是奇数,则n变为3n+1,否则n变为n/2;
(4)转入第(2)步。
克拉兹问题的特殊之处在于:尽管很容易将这个问题讲清楚,但直到今天仍不能保证这个问题的算法对所有可能的输入都有效——即至今没有人证明对所有的正整数该过程都终止。
例如:n=9时,有 9 28 14 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1。
编写程序计算冰雹序列:

import java.util.Arrays;

public class HailstoneSequence {


    public static void main(String[] args) {
        String[] temp = getHailstoneLength(7).split(",");
        System.out.println("序列长度:" + temp.length);
        System.out.println(Arrays.toString(temp));
    }

    public static String getHailstoneLength(int number){

        StringBuilder sb = new StringBuilder(number + "");

        while (number > 1) {
            number = (number % 2 == 0) ? number / 2 : 3 * number + 1;
            sb.append("," + number);
        }
        return sb.toString();
    }
}

以上的程序的正确性看似是不言而喻的,但是仔细观察:n的大小和序列的长度似乎是不成正比的,有些很小的数例如:27的序列就比较长。那么问题来了:对于任意的一个序列,长度是否是有限的?目前还没有结论。——以上的小程序未必是一个算法。

生产者和消费者问题

这是一个经典的同步、等待与唤醒的问题。
生产者不断生产信息,并将信息放在一个指定的区域之中;而消费者则从此区域中不断取走数据。
分析:既然生产的是信息,就可以定义一个信息类,生产者和消费者都占有这个信息类的引用——可以通过信息类将生产者和消费者两个线程联系在一起。
在本例中,生产者生产两类信息:Tom—>tom@tom.com 和Jack—>jack@jack.com 。这两种信息交替出现。
信息类Info

public class Info {

    private String name ;
    private String email ;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }

}

生产者类Producer

public class Producer implements Runnable{

    private Info info; // 持有信息类的引用

    /**
     * 通过构造方法设置info的内容
     * @param info
     */
    public Producer(Info info) {
        this.info = info;
    }



    @Override
    public void run() {

        boolean flag = false; // 定义标记位
        for(int i = 0;i < 50;i++){
            if (flag) {
                info.setName("Tom");
                try {
                    Thread.sleep(90);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                info.setEmail("tom@tom.com");
                flag = false;
            }else {
                info.setName("Jack");
                try {
                    Thread.sleep(90);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                info.setEmail("jack@jack.com");
                flag = true;
            }

        }
    }

}

消费者类Customer

public class Customer implements Runnable{

    private Info info; // 持有信息类的引用

    /**
     * 通过构造方法给info赋值
     * @param info
     */
    public Customer(Info info) {
        this.info = info;
    }

    @Override
    public void run() {

        for (int i = 0; i < 50; i++) {
            try {
                Thread.sleep(90);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(info.getName()+"---->" + info.getEmail());
        }

    }

}

测试类ProducerAndCustomerTest

public class ProducerAndCustomerTest {

    public static void main(String[] args) {

        Info info = new Info(); // 生产者和消费者持有的信息类的引用
        Producer producer = new Producer(info);
        Customer customer = new Customer(info);

        new Thread(producer).start();
        new Thread(customer).start();
    }

}

运行结果:
这里写图片描述
之所以出现了内容不匹配是因为中间加入了延迟操作,因而可能导致不同步的问题,可以使用同步解决这个问题。
更改代码如下:将姓名和邮箱的设置封装成一个同步方法set方法;将取得姓名和邮箱的操作封装成一个同步方法get方法。
Info.java

public class Info {

    private String name ;
    private String email ;

    /**
     * 设置信息的同步方法
     * @param name
     * @param email
     */
    public synchronized void set(String name,String email){

        this.name = name;
        try {
            Thread.sleep(90);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.email = email;
    }

    /**
     * 取出信息的同步方法
     */
    public synchronized void get(){

        try {
            Thread.sleep(90);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(this.name + "--->" + this.email);
    }

}

Producer.java

public class Producer implements Runnable{

    private Info info; // 持有信息类的引用

    /**
     * 通过构造方法设置info的内容
     * @param info
     */
    public Producer(Info info) {
        this.info = info;
    }

    @Override
    public void run() {

        boolean flag = false; // 定义标记位
        for(int i = 0;i < 50;i++){
            if (flag) {
                info.set("Tom", "tom@tom.com");
                flag = false;
            }else {
                info.set("Jack", "jack@jack.com");
                flag = true;
            }

        }
    }

}

Customer.java

public class Customer implements Runnable{

    private Info info; // 持有信息类的引用

    /**
     * 通过构造方法给info赋值
     * @param info
     */
    public Customer(Info info) {
        this.info = info;
    }

    @Override
    public void run() {

        for (int i = 0; i < 50; i++) {
            info.get();
        }

    }

}

这里写图片描述
以上代码并没有达到设置一个取走一个的效果
必须依靠一种等待和唤醒的机制。可以增加一个boolean类型的标志位,此标志位为true表示可以生产但不能取走,此时的消费者线程应该等待;如果标志位为false表示可以取走但是不能生产,此时的生产者应该等待。
这里写图片描述
直接修改Info类,增加等待和唤醒机制
Info.java

public class Info {

    private String name ;
    private String email ;

    boolean flag = true; // 设置标志位,刚开始的时候可以生产但不能取走

    /**
     * 生产信息的同步方法
     * @param name
     * @param email
     */
    public synchronized void set(String name,String email){

        if(!flag){
            try {
                super.wait();  //等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.name = name;
        try {
            Thread.sleep(90);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.email = email;
        flag = false; // 表示可以取走
        super.notify();
    }

    /**
     * 取出信息的同步方法
     */
    public synchronized void get(){

        if (flag) {
            try {
                super.wait(); // 等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        try {
            Thread.sleep(90);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(this.name + "--->" + this.email);
        flag = true; // 表示可以生产
        super.notify();
    }

}

运行结果:
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值