2020-11-21

四、栈:一种受限的线性结构(只能在一端进行插入、删除)。
1、特点:先进后出
2、栈的实现包含:顺序栈和链栈。主要操作:入栈和出栈

1、基于数组的顺讯栈
/*
 * 基于数组实现的顺序栈
 */
public class ArrayStack {
	private int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;// 栈的最大容量
	private int DEFAULT_CAPACITY = 10;// 默认栈容量
	private int top = -1;// 栈顶指针
	private int size = 0;// 记录栈的大小【top和size保留一个就行了】
	private Object element[];// 存放栈内元素

	public ArrayStack() {
		element = new Object[DEFAULT_CAPACITY];
	}

	// 创建指定大小的栈
	public ArrayStack(int capacity) {
		element = new Object[capacity];
	}

	// 入栈
	public boolean push(Object data) {
		// 先检查栈容量是否足够【再进入一个元素时,数组长度是否够?】
		try {
			checkCapacity(size + 1);
			element[++top] = data;
			size++;
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	// 出栈
	public Object pop() {
		if (size <= 0) {
			System.out.println("Stack is null");
			return null;
		}
		size--;
		return element[top--];
	}

	private void checkCapacity(int minCapacity) {
		if (element.length - minCapacity < 0) {
			throw new RuntimeException("栈容量不够");
		}
	}

	// 获得栈的大小
	public int size() {
		return size;
	}

	public static void main(String[] args) {
		ArrayStack stack = new ArrayStack();

		for (int i = 0; i < 13; i++) {
			boolean push = stack.push(i);
			System.out.println("入栈元素" + i + "  ,入栈结果为:" + push);
		}

		for (int i = 0; i < 11; i++) {
			System.out.println(stack.pop());
		}

		System.out.println("现在栈大小为:" + stack.size);
	}
}

2、基于链表的链式栈【单链表/双链表都可以】

/*
 * 基于双链表实现的链式栈
 */
class Node {
	Object data;
	Node prev;// 前驱
	Node next;// 后继

	public Node(Node prev, Object data, Node next) {
		this.data = data;
		this.prev = prev;
		this.next = next;
	}

}

public class LinkedListStack {
	private int size = 0;
	private Node tail;// 一端进行插入、删除

	public LinkedListStack() {
		this.tail = null;
	}

	// 入栈
	public void push(Object data) {
		Node newNode = new Node(tail, data, null);
		if (size > 0) {
			tail.next = newNode;
		}
		tail = newNode;
		size++;
	}

	// 出栈
	public Object pop() {
		if (size < 1) {
			return null;
		}
		Object data = tail.data;
		tail = tail.prev;// 删除前驱
		if (tail != null) {
			tail.next = null;// 删除后继
		}
		size--;
		return data;
	}

	public int size() {
		return size;
	}

	public static void printStack(LinkedListStack stack) {
		if (stack.size() > 0) {
			Node tail = stack.tail;
			while (tail != null) {
				System.out.print(tail.data + "  ");
				tail = tail.prev;
			}
		}
	}

	public static void main(String[] args) {
		LinkedListStack stack = new LinkedListStack();
		for (int i = 0; i < 10; i++) {
			stack.push(i);
		}
		printStack(stack);
	}
}

3、针对栈,Java提供了java.util.Stack类封装了各种操作细节。

1、Stack类常用操作:
	初始化 Stack stack = new Stack();
	入栈 push(E e)
	出栈 pop()
	获得栈顶元素 peek()
	栈大小 size()

2、源码分析:
1)、Stack是用数组实现的顺序栈,底层支持动态扩容,扩容方法grow。
2)、Stack底层存储数据还是用到父类Vector,所以数组初始大小10,增量因子capacityIncrement=0,两倍扩容。

public class Stack<E> extends Vector<E> {
    
	 public Stack() {
	 }
	 
//入栈
    public E push(E item) {
        addElement(item);//调用父类Vector的方法
		return item;
    }
    
    public synchronized void addElement(E obj) {//线程安全
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = obj;
    }
    
    private void ensureCapacityHelper(int minCapacity) {
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);//扩容
    }
    
    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        //两倍扩容
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
                                         
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
} 

五、队列:一种受限的线性结构,只能在一端插入,另一端删除。
1、特点:先进先出
2、主要操作:入队列、出队列。常见队列:循环队列、阻塞队列、并发队列。

1、基于数组实现的顺序队列:
public class ArrayQueue {
	// 定义队列的结构

	private Object elements[];// 存放队列元素
	private int size = 0;// 记录队列大小
	private int DEFAULT_SIZE = 10;// 默认初始容量
	private int front;// 队头
	private int rear;// 队尾
	private int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;// 最大容量【借鉴ArrayList源码】

	// 定义在结构上的操作

	public ArrayQueue() {
		elements = new Object[DEFAULT_SIZE];
		front = -1;
		rear = -1;
	}

	public ArrayQueue(int capacity) {
		elements = new Object[capacity];
		front = -1;
		rear = -1;
	}

	// 入队列【扩容】
	public boolean enqueue(Object data) {
		// 先检查队列容量是否足够
		try {
			ensureSize();
			elements[++rear] = data;
			size++;
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	// 出队列
	public Object dequeue() {
		if (front == rear) {
			return null;
		}
		Object data = elements[++front];
		size--;
		return data;
	}

	// 打印队列元素
	public void printQueue() {
		for (int i = 0; i <= rear; i++) {
			System.out.print(elements[i] + "  ");
		}
	}

	// 入队列前检查容量是否足够
	private void ensureSize() {
		if (rear == elements.length - 1) {// 不能再继续入队列了
			if (front == -1) {// 队列从未删除元素
				grow(size);// 直接扩容

			} else {// 队列删除过元素,将所有元素搬到从下标0开始处【解决了假溢出!!!】
				for (int i = front + 1; i <= rear; i++) {
					elements[i - front - 1] = elements[i];
				}
				rear = rear - front - 1;
				front = -1;
			}
		}
	}

	// 动态扩容
	public void grow(int oldSize) {
		int newSize = oldSize + (oldSize >> 1);// 1.5倍扩容
		if (newSize - oldSize < 0) {
			newSize = DEFAULT_SIZE;
		}
		elements = Arrays.copyOf(elements, newSize);
	}

	public static void main(String[] args) {
		ArrayQueue queue = new ArrayQueue();

		// for (int i = 0; i < 12; i++) {
		// queue.enqueue(i + 1);
		// }
		for (int i = 0; i < 9; i++) {
			queue.enqueue(i + 1);
		}
		queue.dequeue();// 1出队列
		queue.enqueue(10);
		queue.enqueue(20);

		queue.printQueue();

	}
}

2、基于链表实现的队列:
/*
 * 基于单链表实现队列(双链表也可以)
 */
public class LinkedListQueue {
	// 定义链表的结构
	static class Node {
		Object data;
		Node next;

		public Node(Object data) {
			this.data = data;
		}
	}

	// 定义队列的结构
	private int size;// 队列中元素个数
	private Node front;// 队头结点
	private Node rear;// 队尾结点

	public LinkedListQueue() {// 还可以添加setter/getter方法
		front = null;
		rear = null;
		size = 0;
	}

	// 定义队列的操作【还可以添加获得队头、队尾元素、打印队列等操作加以完善】

	// 入队【链表不需要扩容】
	public void enqueue(Object element) {
		Node node = new Node(element);
		if (rear == null) {// 队尾为空,则第一个插入结点为队尾、队头结点
			rear = node;
			front = node;
			size++;
			return;
		}
		rear.next = node;
		rear = node;
		size++;
	}

	// 出队
	public Object dequeue() {
		if (front != null && front.next != null) {
			Object element = front.data;
			front = front.next;
			size--;
			return element;
		}
		if (front != null && front.next == null) {
			Object element = front.data;
			front = null;
			size = 0;
			System.out.println("这是最后一个元素了,不要在出队列了");
			return element;
		} else {
			return null;
		}
	}

	public static void main(String[] args) {
		LinkedListQueue queue = new LinkedListQueue();

		for (int i = 0; i < 10; i++) {
			System.out.println("Enqueue--->" + (i + 1));
			queue.enqueue(i + 1);
		}
		for (int i = 0; i < 10; i++) {
			queue.dequeue();
		}
		System.out.println(queue.size);
	}
}

3、队列的主要应用场景:用队列来存放等待处理的元素,这种场景一般用于缓冲、并发访问、实时消息通信、分布式消息队列等。
总结:对于在很短时间内可以处理的消息,不需要队列,直接阻塞即可。但是如果在消息处理时费时间,就可以引入队列,避免阻塞

4、针对队列,Java提供了java.util.Queue接口:

Queue接口方法:(它继承自Collection接口)
 add(E e) 插入一个元素到队列中,失败时返回IllegalStateException (队列容量不够)
 offer(E e) 插入一个元素到队列中,失败时返回false
 
 element() 返回队列头部的元素
 peek() 返回队列头部的元素,队列为空时返回null
 
 poll() 返回并移除队列的头部元素,队列为空时返回null
 remove() 返回并移除队列的头部元素
 
再有Queue接口的两个子接口Deque、BlockingQueue。

`

六、题目:

1、用两个栈模拟一个队列

2、用两个队列模拟一个栈

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以通过Java中的日期时间类 `LocalDate` 和 `LocalDateTime` 来实现该功能。 首先,我们需要将时间段转换为 `LocalDateTime` 对象,然后将时间部分设置为 00:00:00 或 23:59:59,最后遍历每一天,获取每一天的开始时间和结束时间。 以下是代码示例: ```java import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.format.DateTimeFormatter; public class TimeUtils { public static void main(String[] args) { String startStr = "2020-11-20 09:09:09"; String endStr = "2021-10-09 10:10:10"; DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); LocalDateTime start = LocalDateTime.parse(startStr, formatter); LocalDateTime end = LocalDateTime.parse(endStr, formatter); // 将时间部分设置为 00:00:00 或 23:59:59 LocalDateTime startOfDay = start.with(LocalTime.MIN); LocalDateTime endOfDay = end.with(LocalTime.MAX); // 遍历每一天,获取每一天的开始时间和结束时间 LocalDate startDate = startOfDay.toLocalDate(); LocalDate endDate = endOfDay.toLocalDate(); while (!startDate.isAfter(endDate)) { LocalDateTime startOfDayOfDate = startDate.atStartOfDay(); LocalDateTime endOfDayOfDate = startDate.atTime(LocalTime.MAX); System.out.println("Start time of " + startDate + ": " + startOfDayOfDate); System.out.println("End time of " + startDate + ": " + endOfDayOfDate); startDate = startDate.plusDays(1); } } } ``` 输出结果如下: ``` Start time of 2020-11-20: 2020-11-20T00:00 End time of 2020-11-20: 2020-11-20T23:59:59.999999999 Start time of 2020-11-21: 2020-11-21T00:00 End time of 2020-11-21: 2020-11-21T23:59:59.999999999 ... Start time of 2021-10-09: 2021-10-09T00:00 End time of 2021-10-09: 2021-10-09T23:59:59.999999999 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值