第一篇:队列、栈、链表

1 说明

1.1 最近准备学习下数据结构与算法,顺便把笔记记录下来。
1.2 所有功能采用Java代码简单实现,不考虑高并发线程安全问题。
1.3 本人菜鸟一枚,如有错误,欢迎批评指正。

2 队列

队列是个有序的列表,遵循先进先出原则,这里我用数组来实现。

2.1 代码实现
2.1.1 定义一个接口IQueue
package com.wanzh.queue;

public interface IQueue<T> {
	/**
	 * 插入元素
	 * @param t 
	 * @return
	 */
	public boolean push(T t);
	
	/**
	 * 插入元素
	 * @param t 插入的元素
	 * @param isExtend 容量不够是否扩容
	 * @return
	 */
	public boolean push(T t, boolean isExtend);
	/**
	 * 弹出元素
	 * @return
	 */
	public T pop();
	/**
	 * 获取队列第一个元素
	 * @return
	 */
	public T element();
	/**
	 * 获取队列所有元素
	 * @return
	 */
	public T[] elements();
	/**
	 * 获取队列大小
	 * @return
	 */
	public int  size();
	/**
	 * 判断队列是否为空
	 * @return
	 */
	public boolean isEmpty();
	
	/**
	 * 判断队列是否满
	 * @return
	 */
	public boolean isFull();
}


2.1.2 编写实现类MyQueue
package com.wanzh.queue.impl;

import com.wanzh.queue.IQueue;

@SuppressWarnings("unchecked")
public class MyQueue<T> implements IQueue<T> {
	private Object[] elements;//队列元素
	private int capacity;//容量
	private int header;//头指针
	private int footer;//尾指针
	private int size;//当前队列大小
	private int rate;//扩容的倍数
	
	/**
	 * 初始化队列
	 * @param capacity 队列容量
	 */
	public MyQueue(int capacity) {
		this.capacity = capacity;
		elements =new Object[capacity];
		rate = 2;
	}
	
	/**
	 * 插入元素
	 * @param t 
	 * @return
	 */
	@Override
	public boolean push(T t) {
		return push(t, false);
	}
	
	/**
	 * 插入元素
	 * @param t 插入的元素
	 * @param isExtend 容量不够是否扩容
	 * @return
	 */
	public boolean push(T t, boolean isExtend) {
		if(isFull()) {
			if(isExtend) {
				extend();
			}else {
				System.out.println("当前队列已满,无法插入元素"+t);
				return false;
			}
		}
		elements[footer] = t;
		//将尾指针指向下一个要插入的位置下标
		footer = (footer + 1) % capacity;
		size ++;
		return true;
	}
	
	/**
	 * 对数组进行扩容
	 */
	private void extend() {
		//获取有序的数组
		T[] elements = elements();
		//容量以rate倍增长
		capacity *= rate;
		//对数组进行扩容
		Object[] target = new Object[capacity];
		System.arraycopy(elements, 0, target, 0, size);
		this.elements = target;
		//调整首尾指针的下标位置
		footer = size;
		header = 0;
	}
	
	/**
	 * 弹出元素
	 * @return
	 */
	@Override
	public T pop() {
		if(isEmpty()) {
			System.out.println("当前队列已空,无法弹出元素");
			return null;
		}
		Object head = elements[header];
		//将头指针指向下一个要弹出的元素的位置下标
		header = (header + 1) % capacity;
		size --;
		return (T) head;
	}
	
	/**
	 * 获取队列第一个元素
	 * @return
	 */
	@Override
	public T element() {
		if(isEmpty()) {
			System.out.println("当前队列已空,无法获取元素");
			return null;
		}
		return (T) elements[header];
	}
	
	/**
	 * 获取队列所有元素
	 * @return
	 */
	@Override
	public T[] elements() {
		if(isEmpty()) {
			System.out.println("当前队列已空,无法获取元素");
			return null;
		}
		Object[] target= new Object[size];
		for (int i = header, j = 0; i < header + size ; i++, j++) {
			target[j] = elements[i % capacity];
		}
		return (T[]) target;
	}
	
	/**
	 * 获取队列大小
	 * @return
	 */
	@Override
	public int size() {
		return size ;
	}
	
	/**
	 * 判断队列是否为空
	 * @return
	 */
	@Override
	public boolean isEmpty() {
		return size == 0;
	}
	
	/**
	 * 判断队列是否满
	 * @return
	 */
	@Override
	public boolean isFull() {
		return size == capacity;
	}

}


2.1.3 编写测试类TestQueue
package com.wanzh.queue.test;

import java.util.Arrays;

import com.wanzh.queue.IQueue;
import com.wanzh.queue.impl.MyQueue;

public class TestQueue {
	public static void main(String[] args) {
		IQueue<Integer> myQueue = new MyQueue<>(3);
		for(int i = 1; i <= 4;i++) {
			myQueue.push(i);
		}
		System.out.println("获取队列第一个元素:"+myQueue.element()+",获取队列所有元素:"+Arrays.toString(myQueue.elements()));
		System.out.println("获取队列大小:"+myQueue.size());
		Integer pop = myQueue.pop();
		System.out.println("弹出元素"+pop+",获取队列第一个元素:"+myQueue.element()+",获取队列所有元素:"+Arrays.toString(myQueue.elements()));
		for(int i = 10; i <= 16;i++) {
			myQueue.push(i,true);
			System.out.println("插入元素"+i+"后,获取队列所有元素:"+Arrays.toString(myQueue.elements()));
		}
		
		
	}
}


运行结果

当前队列已满,无法插入元素4
获取队列第一个元素:1,获取队列所有元素:[1, 2, 3]
获取队列大小:3
弹出元素1,获取队列第一个元素:2,获取队列所有元素:[2, 3]
插入元素10后,获取队列所有元素:[2, 3, 10]
插入元素11后,获取队列所有元素:[2, 3, 10, 11]
插入元素12后,获取队列所有元素:[2, 3, 10, 11, 12]
插入元素13后,获取队列所有元素:[2, 3, 10, 11, 12, 13]
插入元素14后,获取队列所有元素:[2, 3, 10, 11, 12, 13, 14]
插入元素15后,获取队列所有元素:[2, 3, 10, 11, 12, 13, 14, 15]
插入元素16后,获取队列所有元素:[2, 3, 10, 11, 12, 13, 14, 15, 16]

3 栈

先进后出,插入和删除操作只能在一端进行,最先放入的元素在栈底,最后放入的元素在栈顶。

3.1 代码实现
3.1.1 定义一个接口IStack
package com.wanzh.stack;

public interface IStack<T> {
	/**
	 * 插入元素
	 * @param t 
	 * @return
	 */
	public boolean push(T t);
	/**
	 * 插入元素
	 * @param t 插入的元素
	 * @param isExtend 容量不够是否扩容
	 * @return
	 */
	public boolean push(T t, boolean isExtend);
	/**
	 * 弹出元素
	 * @return
	 */
	public T pop();
	/**
	 * 获取栈顶元素
	 * @return
	 */
	public T element();
	/**
	 * 获取栈内所有元素
	 * @return
	 */
	public T[] elements();
	/**
	 * 获取栈大小
	 * @return
	 */
	public int  size();
	/**
	 * 判断栈是否为空
	 * @return
	 */
	public boolean isEmpty();
	
	/**
	 * 判断栈是否满
	 * @return
	 */
	public boolean isFull();
}

3.1.2 编写实现类MyStack
package com.wanzh.stack.impl;



import com.wanzh.stack.IStack;
@SuppressWarnings("unchecked")
public class MyStack<T> implements IStack<T> {

	private Object[] elements;//栈元素
	private int capacity;//容量
	private int size;//当前栈大小
	private int rate;//扩容的倍数
	
	/**
	 * 初始化栈
	 * @param capacity 栈容量
	 */
	public MyStack(int capacity) {
		this.capacity = capacity;
		elements =new Object[capacity];
		rate = 2;
	}

	/**
	 * 插入元素
	 * @param t 
	 * @return
	 */
	@Override
	public boolean push(T t) {
		return push(t, false);
	}

	/**
	 * 插入元素
	 * @param t 插入的元素
	 * @param isExtend 容量不够是否扩容
	 * @return
	 */
	public boolean push(T t, boolean isExtend) {
		if(isFull()) {
			if(isExtend) {
				extend();
			}else {
				System.out.println("当前栈已满,无法插入元素"+t);
				return false;
			}
		}
		elements[size++] = t;
		return true;
	}
	
	/**
	 * 对数组进行扩容
	 */
	private void extend() {
		//容量以rate倍增长
		capacity *= rate;
		//对数组进行扩容
		Object[] target = new Object[capacity];
		System.arraycopy(elements, 0, target, 0, size);
		elements = target;
	}
	
	/**
	 * 弹出元素
	 * @return
	 */
	@Override
	public T pop() {
		if(isEmpty()) {
			System.out.println("当前栈已空,无法弹出元素");
			return null;
		}
		Object head = elements[--size];
		return (T) head;
	}
	
	/**
	 * 获取栈顶元素
	 * @return
	 */
	@Override
	public T element() {
		if(isEmpty()) {
			System.out.println("当前栈已空,无法获取元素");
			return null;
		}
		return (T) elements[size -1];
	}
	
	/**
	 * 获取栈内所有元素
	 * @return
	 */
	@Override
	public T[] elements() {
		if(isEmpty()) {
			System.out.println("当前栈已空,无法获取元素");
			return null;
		}
		Object[] target= new Object[size];
		for (int i = 0; i < size; i++) {
			target[i] = elements[size - i -1];
		}
		return (T[]) target;
	}

	/**
	 * 获取栈大小
	 * @return
	 */
	@Override
	public int size() {
		return size;
	}

	/**
	 * 判断栈是否为空
	 * @return
	 */
	@Override
	public boolean isEmpty() {
		return size == 0;
	}

	/**
	 * 判断栈是否满
	 * @return
	 */
	@Override
	public boolean isFull() {
		return size == capacity;
	}

}

3.1.3 编写测试类TestStack
package com.wanzh.stack.test;

import java.util.Arrays;

import com.wanzh.stack.IStack;
import com.wanzh.stack.impl.MyStack;

public class TestStack {
	public static void main(String[] args) {
		IStack<Integer> myQueue = new MyStack<>(3);
		for(int i = 1; i <= 4;i++) {
			myQueue.push(i);
		}
		System.out.println("获取栈第一个元素:"+myQueue.element()+",获取栈所有元素:"+Arrays.toString(myQueue.elements()));
		System.out.println("获取栈大小:"+myQueue.size());
		Integer pop = myQueue.pop();
		System.out.println("弹出元素"+pop+",获取栈第一个元素:"+myQueue.element()+",获取栈所有元素:"+Arrays.toString(myQueue.elements()));
		for(int i = 10; i <= 16;i++) {
			myQueue.push(i,true);
			System.out.println("插入元素"+i+"后,获取栈所有元素:"+Arrays.toString(myQueue.elements()));
		}
	}
}

运行结果

当前栈已满,无法插入元素4
获取栈第一个元素:3,获取栈所有元素:[3, 2, 1]
获取栈大小:3
弹出元素3,获取栈第一个元素:2,获取栈所有元素:[2, 1]
插入元素10后,获取栈所有元素:[10, 2, 1]
插入元素11后,获取栈所有元素:[11, 10, 2, 1]
插入元素12后,获取栈所有元素:[12, 11, 10, 2, 1]
插入元素13后,获取栈所有元素:[13, 12, 11, 10, 2, 1]
插入元素14后,获取栈所有元素:[14, 13, 12, 11, 10, 2, 1]
插入元素15后,获取栈所有元素:[15, 14, 13, 12, 11, 10, 2, 1]
插入元素16后,获取栈所有元素:[16, 15, 14, 13, 12, 11, 10, 2, 1]

4 链表

链表时以节点的形式存储,每个节点包含两部分:data数据和next下一节点的引用,不是连续存储。

4.1 代码实现
4.1.1 定义一个节点实体类Node
package com.wanzh.chain;

/**
 * 节点类
 */
public class Node<T> implements Cloneable{
	private T data;
	private Node<T> next;
	
	public Node(T data) {
		this.data = data;
	}
	
	public T getData() {
		return data;
	}
	public void setData(T data) {
		this.data = data;
	}
	public Node<T> getNext() {
		return next;
	}
	public void setNext(Node<T> next) {
		this.next = next;
	}
	@Override
	public String toString() {
		return String.valueOf(data);
	}
	
	public Node<T> clone() {
		Node<T> node = null;
        try {
            node = (Node<T>) super.clone();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return node;
    }
	
}

4.1.2 定义一个接口ILinkedList
package com.wanzh.chain;


public interface ILinkedList<T> {

	/**
	 * 添加一个节点
	 * @param node
	 * @return
	 */
	boolean add(Node<T> node);

	/**
	 * 删除一个节点
	 * @param node
	 * @return
	 */
	boolean remove(Node<T> node);

	/**
	 * 获取第一个节点
	 * @return
	 */
	Node<T> getFirst();

	/**
	 * 获取最后一个节点
	 * @return
	 */
	Node<T> getLast();

	/**
	 * 反转链表
	 */
	void reverse();

	/**
	 * 显示链表所有元素
	 */
	void show();

	/**
	 * 获取链表的大小
	 * @return
	 */
	int size();
	/**
	 * 判断链表是否为空
	 * @return
	 */
	boolean isEmpty();
	
	

}

4.1.3 编写实现类SingleLinkedList
package com.wanzh.chain.impl;

import com.wanzh.chain.ILinkedList;
import com.wanzh.chain.Node;

/**
 * 单向链表类
 * @param <T>
 */
public class SingleLinkedList<T> implements ILinkedList<T>{
	
	private Node<T> head;
	
	/**
	 * 添加一个节点
	 * @param node
	 * @return
	 */
	@Override
	public boolean add(Node<T> node) {
		//获取尾节点
		Node<T> last = getLast();
		//若不存在尾节点 说明当前链表元素为空 把加入的元素节点置为头结点
		if(last == null) {
			head = node;
			//若为单向循环链表 需要把头节点的下一个节点指向自己,其它方法稍作更改
			//head.setNext(head);
		//若存在尾结点 则把尾结点的指针指向当前加入的元素
		}else {
			last.setNext(node);
		}
		return true;
	}
	
	
	/**
	 * 删除一个节点
	 * @param node
	 * @return
	 */
	@Override
	public boolean remove(Node<T> node){
		Node<T> current = head;
		Node<T> pre = null;
		while(current != null) {
			if(current == node) {
				//若当前节点为头节点 则把第二个节点置为头结点
				if(pre == null) {
					head = current.getNext();
				//若当前节点不是头节点,则将当前节点的上一个节点指向当前节点的下一个节点地址
				}else {
					pre.setNext(current.getNext());
					current.setNext(null);
				}
				return true;
			}
			pre = current;
			current = current.getNext();
		}
		return false;
	}
	
	
	/**
	 * 获取第一个节点
	 * @return
	 */
	@Override
	public Node<T> getFirst(){
		return head;
	}
	
	/**
	 * 获取最后一个节点
	 * @return
	 */
	@Override
	public Node<T> getLast(){
		if(head == null) {
			return null;
		}
		Node<T> current = head;
		while(current.getNext() != null) {
			current = current.getNext();
		}
		return current;
	}
	
	/**
	 * 反转链表
	 */
	@Override
	public void reverse() {
		if(head == null) {
			System.out.println("当前链表没有元素");
			return ;
		}
		Node<T> current = head;
		Node<T> pre = null;
		Node<T> temp = null;
		while(current != null) {
			temp = current.clone();
			current.setNext(pre);
			pre = current;
			current = temp.getNext();
			
		}
		head = pre;
	}
	
	/**
	 * 显示链表所有元素
	 */
	@Override
	public void show() {
		if(head == null) {
			System.out.println("当前链表没有元素");
			return ;
		}
		Node<T> current = head;
		System.out.print(current);
		while(current.getNext() != null) {
			current = current.getNext();
			System.out.print("->"+current);
		}
		System.out.println();
	}
	
	/**
	 * 获取链表的大小
	 * @return
	 */
	@Override
	public int size() {
		if(head == null) {
			return 0;
		}
		Node<T> current = head;
		int count = 0;
		while(current != null) {
			count ++;
			current = current.getNext();
		}
		return count;
	}
	
	/**
	 * 判断链表是否为空
	 * @return
	 */
	@Override
	public boolean isEmpty() {
		return head == null;
	}
}

4.1.4 编写测试类TestLinkedList
package com.wanzh.chain.test;

import com.wanzh.chain.ILinkedList;
import com.wanzh.chain.Node;
import com.wanzh.chain.impl.SingleLinkedList;

public class TestLinkedList {
	public static void main(String[] args) {
		ILinkedList<Integer> list = new SingleLinkedList<>();
		Node<Integer> node1 = new Node<Integer>(1);
		Node<Integer> node2 = new Node<Integer>(2);
		Node<Integer> node3 = new Node<Integer>(3);
		list.add(node1);
		list.add(node2);
		list.add(node3);
		System.out.println("插入节点1,2,3");
		System.out.print("first:"+list.getFirst()+",last:"+list.getLast()+",size:"+list.size()+",show:");
		list.show();
		System.out.println("反转链表");
		list.reverse();
		System.out.print("first:"+list.getFirst()+",last:"+list.getLast()+",size:"+list.size()+",show:");
		list.show();
		System.out.println("节点是否为空"+list.isEmpty());
		System.out.println("删除节点2:"+list.remove(node2));
		System.out.print("first:"+list.getFirst()+",last:"+list.getLast()+",size:"+list.size()+",show:");
		list.show();
		System.out.println("删除节点1:"+list.remove(node1));
		System.out.print("first:"+list.getFirst()+",last:"+list.getLast()+",size:"+list.size()+",show:");
		list.show();
		System.out.println("删除节点2:"+list.remove(node2));
		System.out.println("删除节点3:"+list.remove(node3));
		System.out.println("节点是否为空"+list.isEmpty());
		System.out.print("first:"+list.getFirst()+",last:"+list.getLast()+",size:"+list.size()+",show:");
		list.show();
		
	}
}

运行结果

插入节点1,2,3
first:1,last:3,size:3,show:1->2->3
反转链表
first:3,last:1,size:3,show:3->2->1
节点是否为空false
删除节点2:true
first:3,last:1,size:2,show:3->1
删除节点1:true
first:3,last:3,size:1,show:3
删除节点2:false
删除节点3:true
节点是否为空true
first:null,last:null,size:0,show:当前链表没有元素
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值