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:当前链表没有元素