数据结构(java合集)

数据结构(java合集)

0.基本说明

0.1数据结构概念的三个方面:

0.1.1逻辑结构
  • 线性结构(数据元素之间存在着“一对一”的线性关系的数据结构)
  • 树结构(数据元素之间存在层次关系,即“一对多”的发散性树状的数据结构)
  • 图结构(任意数据元素之间都可以相邻,形成“多对多”的数据结构)
0.1.2存储结构
  • 顺序存储结构
  • 链式存储结构
0.1.3对数据的操作
  1. 初始化(构建构造方法,初始化类中的属性
  2. 判断是否有数据(isEmpty()
  3. 存取,指设置或取出get()set())指定数据元素
  4. 遍历(traverse),指按照某种次序访问一次数据结构中的全部元素
  5. 统计数据元素(size
  6. 对数据结构中的元素进行增删查改(crud)操作,注: 非必要操作
  7. 比较相等(equals()
  8. 深拷贝(copy()),复制数据结构及其所有元素
  9. 排序(sort()),将数据元素按某种顺序进行元素的重新排序
0.1.4算法的特点
  1. 有穷性
  2. 确定性
  3. 可行性
  4. 有输入
  5. 有输出
0.1.5算法的设计目标
  1. 正确性
  2. 健壮性
  3. 高时间效率
  4. 高空间效率
  5. 可读性

1.顺序表(数组)

1.1基本分析

1.1.1概念与物理模型
  1. 顺序表(静态一维数组)逻辑结构上属于线性结构存储结构也是显而易见的顺序存储结构

  2. 数组是具有固定长度的用于存储相同数据类型的数据结构

  3. 数组中的元素会被储存在一段连续的内存空间

    分析:静态数组一旦被定义后,占用的内存空间就是固定且连续的,容量就是不可改变的。既不能在任何位置插入元素,也不能在任何位置删除元素,只能读取和修改元素,因而在我们设计的动态数组中,要实现插入和删除操作就尤为重要

1.2对数据的基本操作

1.2.1属性定义
  • Object[] data 用于存储数据
  • int size 用于记录数组中的元素个数
1.2.2方法定义
方法名备注
public Array()无参构造方法:没有任何赋值情况下,默认构建一个长度是10的数组。
public Array(int capacity)构造方法:有一个整形参数,用于规定数组长度
private Array(T[] data)构造方法:有一个已储存数据的数组,将数组中的数据放入data数组中
public int getCapapcity()获取数组的实际容量
public int getSize()获取数组的数据元素个数
public boolean isEmpty()判断数组是否为空
public T get(int index)根据下标获取数据元素
public void set(int index, T e)修改指定位置的数据元素
public boolean contains(T e)查询数组中是否存在某个数据元素
public void addFirst(T e)将数据元素添加在数组的最前端
public void add(int index, T e)将数据元素添加在指定位置处
public void addLast(T e)将数据元素添加在数组的末端
public T removeFirst()删除首个数据元素,并将数据值返回
public T remove(int index)删除指定位置的数据元素,并将其数据值返回
public T removeLast()删除最后一个数据元素,并将其数据值返回
public void expand()扩大数组容量
public String toString()重写toString方法

1.3具体实现

package myArrayList;

import java.util.Arrays;

public class Array<T> {
	private Object[] data;
	private int size;

	// 无参构造方法:没有任何赋值情况下,默认构建一个长度是10的数组。
	public Array() {
		this.data = new Object[10];
		size = 0;
	}

	// 构造方法:有一个整形参数,用于规定数组长度
	public Array(int capacity) {
		this.data = new Object[capacity + 10];
		size = 0;
	}

	// 构造方法:有一个已储存数据的数组,将数组中的数据放入data数组中
	private Array(T[] data) {
		this.data = new Object[data.length];
		for (int i = 0; i < data.length; i++) {
			this.data[i] = data[i];
		}
		size = data.length;
	}

	// 获取数组的容量
	public int getCapapcity() {
		return data.length;
	}

	// 获取数组中的元素个数
	public int getSize() {
		return size;
	}

	// 获取数组是否为空
	public boolean isEmpty() {
		return size == 0;
	}

	// 根据index索引位置获取元素
	public T get(int index) {
		if (index < 0 || index >= size) {
			throw new IllegalArgumentException("failes,index is illegal");
		}
		return (T) data[index];
	}

	// 修改index处位置的元素为e
	public void set(int index, T e) {
		if (index < 0 || index >= size) {
			throw new IllegalArgumentException("failes,index is illegal");
		}
		data[index] = e;
	}

	// 查看元素中是否包含元素e
	public boolean contains(T e) {
		for (int i = 0; i < size; i++) {
			if (data[i] == e) {
				return true;
			}
		}
		return false;
	}

	// 在所有元素前添加一个新元素添加元素
	public void addFirst(T e) {
		add(0, e);
	}

	// 在第index个位置插入元素e
	public void add(int index, T e) {
		if (size == data.length) {
			//判断数组长度与元素数量是否相等,若相等,则数组中已没有空间存储数据元素
			throw new IllegalArgumentException("failed;array is full");
		}
		if (index < 0 || index > size) {
			//判断给定下标不能小于0或大于size(数组元素的数量)
			throw new IllegalArgumentException("failed;index  >= 0 and  index <=size");
		}
		if (size >= data.length - 10) {
			//判断数组中空间是否充裕,若空间不足则扩充数组空间
			expand();
		}

		//创建新数组,用于储存原数组的全部数据元素和新加入的元素
		Object[] nData = new Object[data.length + 1];
		
		//1.将给定下标前的元素直接转移到新数组中
		for (int i = 0; i < index; i++)
			nData[i] = data[i];

		//2.当到达指定下标位置,将e放入数组
		nData[index] = e;

		//3.原数组中还没存放的元素接着转移到新数组中
		for (int i = index; i < size; i++)
			nData[i + 1] = data[i];

		//将新数组替换旧数组
		data = Arrays.copyOf(nData, data.length);
		//数据元素+1
		size++;
	}

	// 向所有元素后添加一个新元素
	public void addLast(T e) {
		this.add(size + 1, e);
	}

	// 从数组中删除第一个元素,返回删除的元素
	public T removeFirst() {
		return remove(0);
	}

	// 从数组中删除index位置的元素,返回删除的元素
	public T remove(int index) {
		if (index < 0 || index >= size) {
			//判断给定下标不能小于0或大于size(数组元素的数量)
			throw new IllegalArgumentException("failes,index is illegal");
		}
		
		//提取给定下标位置中的数据并返回出去
		T ret = (T) data[index];

		创建新数组,用于储存原数组中 除了被删除元素以外 的其他全部数据元素
		Object[] nData = new Object[data.length - 1];
		
		//1.将给定下标前的元素直接转移到新数组中
		for (int i = 0; i < index; i++)
			nData[i] = data[i];

		//2.将给定下标后的元素也赋值到新元素中
		for (int i = index; i < size; i++)
			nData[i] = data[i + 1];

		//将新数组替换旧数组
		data = Arrays.copyOf(nData, data.length);
		//数据元素-1
		size--;
		return ret;
	}

	// 从数组中删除最后一个元素,返回删除元素。
	public T removeLast() {
		return remove(size - 1);
	}

	// 扩大数组容量
	public void expand() {
		int len = data.length;
		data = Arrays.copyOf(data, len + 10);
	}

	@Override
	public String toString() {
		StringBuilder res = new StringBuilder();
		res.append(String.format("Array: size = %d,capacity = %d \n", size, data.length));
		res.append("[");
		for (int i = 0; i < size; i++) {
			res.append(data[i]);
			if (i != size - 1) {
				res.append(", ");
			}

		}
		res.append("]");
		return res.toString();
	}

}

1.4重要方法

1.4.1在给定位置添加新元素
	// 在第index个位置插入元素e
	public void add(int index, T e) {
		if (size == data.length) {
			//判断数组长度与元素数量是否相等,若相等,则数组中已没有空间存储数据元素
			throw new IllegalArgumentException("failed;array is full");
		}
		if (index < 0 || index > size) {
			//判断给定下标不能小于0或大于size(数组元素的数量)
			throw new IllegalArgumentException("failed;index  >= 0 and  index <=size");
		}
		if (size >= data.length - 10) {
			//判断数组中空间是否充裕,若空间不足则扩充数组空间
			expand();
		}

		//创建新数组,用于储存原数组的全部数据元素和新加入的元素
		Object[] nData = new Object[data.length + 1];
		
		//1.将给定下标前的元素直接转移到新数组中
		for (int i = 0; i < index; i++)
			nData[i] = data[i];

		//2.当到达指定下标位置,将e放入数组
		nData[index] = e;

		//3.原数组中还没存放的元素接着转移到新数组中
		for (int i = index; i < size; i++)
			nData[i + 1] = data[i];

		//将新数组替换旧数组
		data = Arrays.copyOf(nData, data.length);
		//数据元素+1
		size++;
	}
1.4.2在给定位置删除指定元素
// 从数组中删除index位置的元素,返回删除的元素
	public T remove(int index) {
		if (index < 0 || index >= size) {
			//判断给定下标不能小于0或大于size(数组元素的数量)
			throw new IllegalArgumentException("failes,index is illegal");
		}
		
		//提取给定下标位置中的数据并返回出去
		T ret = (T) data[index];

		创建新数组,用于储存原数组中 除了被删除元素以外 的其他全部数据元素
		Object[] nData = new Object[data.length - 1];
		
		//1.将给定下标前的元素直接转移到新数组中
		for (int i = 0; i < index; i++)
			nData[i] = data[i];

		//2.将给定下标后的元素也赋值到新元素中
		for (int i = index; i < size; i++)
			nData[i] = data[i + 1];

		//将新数组替换旧数组
		data = Arrays.copyOf(nData, data.length);
		//数据元素-1
		size--;
		return ret;
	}

2.链表

2.1单链表

2.1.1结构分析
  1. 链表是一种物理存储单元(结点)上非连续、非顺序的链式存储结构组成。

  2. 每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域

  3. 在单链表中,数据域用于存储数据元素,而指针域用于追溯下一个结点的位置

    分析:单链表由于是通过结点指针相连的特点,每次定位某个结点都需要对链表进行遍历,但是因为链表不需要预先知道数据大小。因而,链表结构虽然遍历的时间较长,但是链表可以充分利用计算机内存空间,实现灵活的内存动态管理

2.1.2数据的基本操作
  1. 1结点的属性定义:

    • public T data;
    • public Node next;

    2结点的方法定义:

    方法名备注
    public Node(T data, Node next)有参构造方法:data为数据域,next为指针域
    public Node()无参构造方法:设置数据域和指针域为空
    public Node(T data)有参构造函数:data为数据域,但指针域为空
    public boolean hasNext()判断结点是否有指针域
  2. 1链表的属性定义:

    • private Node head;
    • private int size;

    2链表的方法定义:

    方法名备注
    public Linked()无参构造方法
    public Linked(Node node)有参构造方法:输入一个新结点
    public Linked(T data)有参构造方法:输入一个数据元素
    public boolean isEmpty()判断链表是否为空
    public int getSize()获取链表长度
    public Node get(int index)通过给定下标获取结点
    public void addFirst(T t)在链表头部插入一个新数据元素
    public void addLast(T t)在链表尾部插入一个新数据元素
    public void add(T t, int index)在链表的指定位置插入一个新数据元素
    public void remove(T t)在链表中删除指定数据元素
    public T removeFirst()删除链表的第一个元素
    public T removeLast()删除链表的最后一个元素
    public Node search(T t)根据给定数据t搜索链表中的结点
2.1.3具体实现

1.结点

public class Node<T> {
	public T data;
	public Node next;
	
	public Node() {
		// TODO Auto-generated constructor stub
		this(null,null);
	}

	public Node(T data, Node next) {
		super();
		this.data = data;
		this.next = next;
	}
	
	public Node(T data) {
		this(data,null);
	}

	public boolean hasNext() {
		return next!=null;
	}
}

2.链表

package myLinkedList.Linked;

public class Linked<T> {
	private Node head;
	private int size;

	public Linked() {
		// TODO Auto-generated constructor stub
		head.next = null;
		size = 0;
	}

	public Linked(Node node) {
		if (head.hasNext()) {
			node = head.next;
			while (node.hasNext()) {
				node = node.next;
			}
		} else {
			node = head.next;
		}
		size++;
	}

	public Linked(T data) {
		Node node = new Node(data);
		if (head.hasNext()) {
			node = head.next;
			while (node.hasNext()) {
				node = node.next;
			}
		} else {
			node = head.next;
		}
		size++;
	}

	public boolean isEmpty() {
		return size == 0;
	}

	public int getSize() {
		return size;
	}

	public Node get(int index) {
		if (index < 0 || index >= size) {
			throw new IllegalArgumentException("failes,index is illegal");
		} else {
			int i = 0;
			Node node = head.next;
			while (node.hasNext() && i != index) {
				node.next = node;
				i++;
			}
			return node;

		}
	}

	// 链表头部添加元素
	public void addFirst(T t) {
		Node node = new Node(t); // 节点对象
		node.next = this.head.next.next;
		this.head.next = node;
		this.size++;
	}

	// 向链表尾部插入元素
	public void addLast(T t) {
		this.add(t, this.size);
	}

	// 向链表中间插入元素
	public void add(T t, int index) {
		if (index < 0 || index > size) {
            //判断下标不能小于0或大于结点数
			throw new IllegalArgumentException("index is error");
		}
		if (index == 0) {
            //如果下标为0则返回首节点
			this.addFirst(t);
			return;
		}
		Node preNode = this.head.next;
		// 找到要插入节点的前一个节点
		int i = 0;
		while (preNode.hasNext() && i != index) {
			preNode = preNode.next;
			i++;
		}
        //创建新结点
		Node node = new Node(t);
		// 要插入的节点的下一个节点指向preNode节点的下一个节点
		node.next = preNode.next;
		// preNode的下一个节点指向要插入节点node
		preNode.next = node;
        // 结点数+1
		this.size++;
	}

	// 删除链表元素
	public void remove(T t) {
		if (head.next == null) {
			System.out.println("无元素可删除");
			return;
		}
		// 要删除的元素与头结点的元素相同
		while (head.hasNext() && head.next.data.equals(t)) {
			head.next = head.next.next;
			this.size--;
		}
        
		//上面已经对头节点判别是否要进行删除 所以要对头结点的下一个结点进行判别
		Node cur = this.head.next;
		while (cur != null && cur.hasNext()) {
			if (cur.next.data.equals(t)) {
				this.size--;
				cur.next = cur.next.next;
			} else
				cur = cur.next;
		}

	}

	// 删除链表第一个元素
	public T removeFirst() {
		if (this.head == null) {
			System.out.println("无元素可删除");
			return null;
		}
		Node delNode = this.head.next;
		this.head.next = this.head.next.next;
		delNode.next = null;
		this.size--;
		return (T) delNode.data;
	}

	// 删除链表的最后一个元素
	public T removeLast() {
		if (this.head == null) {
			System.out.println("无元素可删除");
			return null;
		}
		// 只有一个元素
		if (this.getSize() == 1) {
			return this.removeFirst();
		}
		Node cur = this.head.next; // 记录当前结点
		Node pre = this.head.next; // 记录要删除结点的前一个结点
		while (cur.hasNext()) {
			pre = cur;
			cur = cur.next;
		}
		pre.next = cur.next;
		this.size--;
		return (T) cur.data;
	}

	//根据给定数据t搜索链表中的结点
	public Node search(T t) {
		Node node=head.next;
		while(node.hasNext()) {
			node=node.next;
			if(node.data.equals(t)) {
				return node;
			}
		}
		throw new IllegalArgumentException("failes,index is illegal");
	}
}

2.2双向链表

2.1.1结构分析
  1. 双向链表中,每个结点都有两个指针,分别指向直接后继和直接前驱

分析:从双向链表中的任意一个结点开始,都可以很方便地访问前驱结点和后继结点。在写代码时要特别注意有没有指针的缺漏

2.1.2数据的基本操作
  1. 1结点的属性定义:

    • public T data;
    • public Node next;

    2结点的方法定义:

    方法名备注
    public DNode(T data, DNode next)有参构造方法:data为数据域,next为指针域
    public DNode()无参构造方法:设置数据域和指针域为空
    public DNode(T data)有参构造函数:data为数据域,但指针域为空
    public boolean hasNext()判断结点是否有指针域
  2. 1链表的属性定义:

    • private DNode head;
    • private DNode last;
    • private int size;

    2链表的方法定义:

    方法名备注
    public Linked()无参构造方法
    public Linked(Node node)有参构造方法:输入一个新结点
    public Linked(T data)有参构造方法:输入一个数据元素
    public boolean isEmpty()判断链表是否为空
    public int getSize()获取链表长度
    public DNode get(int index)通过给定下标获取结点
    public void addFirst(T t)在链表头部插入一个新数据元素
    public void addLast(T t)在链表尾部插入一个新数据元素
    public void add(T t, int index)在链表的指定位置插入一个新数据元素
    public void remove(T t)在链表中删除指定数据元素
    public T removeFirst()删除链表的第一个元素
    public T removeLast()删除链表的最后一个元素
2.1.3具体实现

1.结点

package myLinkedList.DoubleLinked;

public class DNode<T> {
	public T data;
	public DNode next;
	public DNode pre;
	
	public DNode() {
		// TODO Auto-generated constructor stub
		data=null;
		next=null;
		pre=null;
	}
	
	public DNode(T data, DNode next, DNode pre) {
		super();
		this.data = data;
		this.next = next;
		this.pre = pre;
	}
	
	public DNode(T data) {
		this(data,null,null);
	}
	
	public boolean hasNext() {
		return next!=null;
	}
	
	public boolean hasPre() {
		return pre!=null;
	}

}

2.链表

package myLinkedList.DoubleLinked;

public class DoubleLinked<T> {
	private DNode head;
	private DNode last;
	private int size;

	public DoubleLinked() {
		// TODO Auto-generated constructor stub
		head.next = last;
		head.pre = null;
		last.next = null;
		last.pre = head;
		size = 0;
	}

	public DoubleLinked(T data) {
		DNode node = new DNode(data);
		if (head.hasNext()) {
			node = head.next;
			node.pre = head;
			while (node.hasNext()) {
				node = node.next;
				node.pre = node;
			}
		} else {
			node = head.next;
			node.pre = head;
		}
		node.next = last;
		size++;
	}

	public DoubleLinked(DNode node) {
		if (head.hasNext()) {
			node = head.next;
			node.pre = head;
			while (node.hasNext()) {
				node = node.next;
				node.pre = node;
			}
			node.pre = last.pre.pre;
			node.next = last;
		} else {
			node = head.next;
			node.pre = head;
			node.next = last;
		}
		size++;
	}

	public boolean isEmpty() {
		return size == 0;
	}

	public int getSize() {
		return size;
	}

	public DNode get(int index) {
		if (index < 0 || index >= size) {
			throw new IllegalArgumentException("下标不合法,无法检索");
		} else {
			int i = 0;
			if (head.hasNext()) {
				DNode node = head.next;
				node.pre = head;
				while (node.hasNext() && i != index) {
					node.next = node;
					i++;
				}
				return node;
			}
		}
		throw new IllegalArgumentException("链表");

	}

	public void add(T t, int index) {
		if (index < 0 || index > size) {
			throw new IllegalArgumentException("index is error");
		}
		if (index == 0) {
			this.addFirst(t);
			return;
		}
		if (index == size) {
			this.addLast(t);
			return;
		}
		DNode preNode = new DNode<T>();
		// 找到要插入节点的前一个节点
		if (head.hasNext()) {
			int i = 0;
			preNode = this.head.next;
			while (preNode.hasNext() && i < index) {
				preNode = preNode.next;
				i++;
			}
			DNode node = new DNode(t);
			node.next = preNode.next;
			preNode.next = node;
			size++;
		}
		DNode node = new DNode(t);
		// 要插入的节点的下一个节点指向preNode节点的下一个节点
		node.next = preNode.next;
		preNode.pre = node;
		// preNode的下一个节点指向要插入节点node
		preNode.next = node;
		node.pre = preNode;
		this.size++;
	}

	private void addLast(T t) {
		// TODO Auto-generated method stub
		DNode node = new DNode(t);
		node.pre = last.pre.pre;
		node = last.pre;
		node.next = last;
		size++;
	}

	private void addFirst(T t) {
		// TODO Auto-generated method stub
		DNode node = new DNode(t);
		node.next = head.next.next;
		node = head.next;
		node.pre = head;
		size++;
	}

}

3.串(字符串)

3.1基本分析

  1. 串(或字符串)是由零个或多个字符组成的有序序列
  2. 双引号不是串的值,作用只是为了将串和其他结构区分开。
  3. 子串与主串:串中任意个连续字符组成的字符串叫做该串的子串,包含子串的串称为主串。
  4. 存储串的结构有三种:1 定长顺序存储;2 堆分配存储; 3 块链存储。

分析:虽然储存串的结构有三种,但是在java数据结构中一般只用定长顺序存储,即用字符数组储存。堆分配储存一般在C语言中使用较多。块链储存则是用链表储存,因为通过链表储存串时,一个结点只能存储一个或多个字符,若结点分得多则浪费内存,若结点分得少则意义不大,因而在java的数据结构中以定长顺序存储为主

3.2对数据的基本操作

3.2.1类定义和接口实现
  • class myString implements Comparable, Serializable

说明:通过继承接口实现可比较接口和序列化接口

3.2.2属性定义
  • char[] data;
3.2.3方法定义
方法名备注
public myString()无参构造方法
public myString(myString str)传递一个myString对象
public myString(char[] data, int start, int end)传递一个字符数组,但是只截取从start到end的数据
public myString(char[] data)传递一个字符数组
public int getLength()获取串长度
public char charAt(int index)获取给定位置下的字符数据
public String toString()重写toString方法,将串输出
public int compareTo(myString str)重写compareTo方法,比较两个串的大小
public void insert(char[] chars, int index)将字符数组插入到给定位置
public void insertFirst(char[] chars)将字符数组插入到串的最前端
public void insertLast(char[] chars)将字符数组插入到串的最末端
public void insertString(myString str, int index)将另一个串插入到本串的给定位置
public void remove(int index)将给定位置的字符在串中删除
public void remove(char[] chars, int index)将给定位置的字符数组在串中删除
public void removeString(myString str, int index)将给定位置的串在串中删除
public int index(myString str)Brute-Force算法(1)
public int index(myString str, int begin)Brute-Force算法(2)
public static int[] getNext(String sub)KMP算法(1)
public static int kmp(String src, String sub)KMP算法(2)
public int equals(myString str)判断两个串是否相等

3.3具体实现

3.4重要方法

3.4.1Brute-Force算法
  1. 算法分析

    又称:简单模式匹配算法,其基本思路是:Brute-Force是普通的模式匹配算法。将主串S的第1个字符和模式T的第1个字符比较,若相等,继续逐个比较后续字符;若不等,从主串的下一字符起,重新与模式的第一个字符比较,直到主串的一个连续子串字符序列与模式相等 ,返回值为S中与T匹配的子序列第一个字符的序号,即匹配成功;否则,匹配失败,返回值 -1。

    img

    ​ 算法特点:

    ​ 每次遇到匹配不成功的情况,指针i都要移到本次匹配的开始位置的下一位,称这样的指针移动为回溯
    ​ 指针的回溯越多,简单模式匹配的执行次数越多,所以这种算法一般适用于匹配简单字符串

    ​ 算法优点:

    ​ 算法简单明朗,便于实现记忆。

    ​ 算法缺点:

    ​ 算法效率不高,适用性不强

  2. 算法实现

    public int index(myString str) {
    		return this.index(str, 0);
    	}
    
    	// Brute-Force算法
    	public int index(myString str, int begin) {
    
    		int i = begin, j = 0;
    		int len1 = this.getLength();
    		int len2 = str.getLength();
    		if (begin < 0)
    			begin = 0;
    		if (len1 == 0 || len1 < len2 || begin >= len1)
    			return -1;
    		while (i < len1 && j < len2) {
    			if (this.charAt(i) == str.charAt(j)) {
    				i++;
    				j++;
    			} else {
    				i = i - j + 1;
    				j = 0;
    				if (i > len1 - len2)
    					break;
    			}
    		}
    
    		return j == len2 ? i - len2 : -1;
    	}
    
3.4.2KMP算法
  1. 算法分析

    KMP算法是BF算法的改进版,本质思想是:每当匹配过程中出现字符串比较不等时,不需回溯指针,而是利用已经得到的“部分匹配”结果将模式向右滑动尽可能远的一段距离,继续进行比较。

    img

  2. 算法实现

    public static int[] getNext(String sub) {
    		int j = 1, k = 0;
    		int[] next = new int[sub.length()];
    		next[0] = -1;
    		next[1] = 0;
    
    		while (j < sub.length() - 1) {
    			if (sub.charAt(j) == sub.charAt(k)) {
    				next[j + 1] = k + 1;
    				j++;
    				k++;
    			} else if (k == 0) {
    				next[j + 1] = 0;
    				j++;
    			} else {
    				k = next[k];
    			}
    		}
    		return next;
    	}
    
    	// 根据给定主串和子串,采用KMP算法
    	public static int kmp(String src, String sub) {
    		// 先生成模式串sub的next[j]
    		int[] next = getNext(sub);
    
    		// i:主串的游标
    		// j:子串的游标
    		int i = 0, j = 0, index = -1;
    		while (i < src.length() && j < sub.length()) {
    			if (src.charAt(i) == sub.charAt(j)) {
    				i++;
    				j++;
    			} else if (j == 0) {
    				i++;
    			} else {
    				j = next[j]; // 向右滑动
    			}
    
    		}
    		if (j == sub.length()) {
    			index = i - sub.length();
    		}
    		return index;
    	}
    

4.栈

2.1顺序栈

2.1.1结构分析
2.1.2数据的基本操作

1.属性定义

private Object[] stack;
private int size ;

2.方法定义

方法名备注
public Arraystack()无参构造方法,初始化创建一个长度为10的空数组
public Arraystack(T[] data)有参构造方法,创建一个长度比数据多10的数组,并传入数据
public boolean isEmpty()判断栈是否为空
public int getSize()获取栈元素的个数
public T peek()返回栈顶元素
public void push(T t)入栈
public T pop()出栈
public void expand()扩大栈容量
2.1.3具体实现
package myStack;

import java.util.Arrays;

public class Arraystack<T> {
	private Object[] stack;
	private int size = 0;

	public Arraystack() {
		// TODO Auto-generated constructor stub
		stack = new Object[10];
	}

	Arraystack(int length) {
		stack = new Object[length];
	}

	public Arraystack(T[] data) {
		stack = new Object[data.length + 10];
		for (int i = 0; i < data.length; i++) {
			stack[i] = data[i];
		}
		size = data.length;
	}

	public boolean isEmpty() {
		return size == 0;
	}
	
	public int getSize() {
		return size;
	}

	//返回栈顶元素
	public T peek() {
		T t = null;
		if (!isEmpty()) {
			t = (T) stack[size - 1];
		}
		return t;
	}
	
	public void push(T t) {
		if(size>=stack.length-10) {
			expand();
		}
		t=(T) stack[size];
		size++;
	}
	
	public T pop() {
		T t = peek();
		if(!isEmpty()) {
			stack[size-1]=null;
			size--;
		}
		return t;
	}
	
	public void expand() {
		int len=stack.length;
		stack=Arrays.copyOf(stack, len+10);
	}
}

2.1.4重要方法
//1.
 public T peek() {
		T t = null;
		if (!isEmpty()) {
			t = (T) stack[size - 1];
		}
		return t;
	}

//2.
public void push(T t) {
		if(size>=stack.length-10) {
			expand();
		}
		t=(T) stack[size];
		size++;
	}

//3.
public T pop() {
		T t = peek();
		if(!isEmpty()) {
			stack[size-1]=null;
			size--;
		}
		return t;
	}

2.2链栈

2.1.1结构分析
2.1.2数据的基本操作

1.结点

1.1属性定义

public T data;
public Node next;

1.2方法定义

方法名备注
public Node()无参构造方法
public Node(T data, Node next)有参构造方法,初始化属性
public Node(T data)有参构造方法,输入数据元素,但没有指针
public boolean hasNext()判断结点是否有指针

2.链表

2.1属性定义

private Object[] stack;
private int size ;

2.2方法定义

方法名备注
public Linkedstack()无参构造函数
public Linkedstack(Node node)有参构造函数,插入一个结点在链表尾部
Linkedstack(T t)有参构造函数,利用数据元素生成结点插入在链表尾部
public boolean isEmpty()判断栈是否为空
public int getSize()获取结点个数
public T peek()获取栈顶结点
public void push(T t)入栈
public T pop() throws IllegalAccessException出栈
2.1.3具体实现

1.结点

package myStack;


public class Node<T> {
	public T data;
	public Node next;
	
	public Node() {
		// TODO Auto-generated constructor stub
		this(null,null);
	}

	public Node(T data, Node next) {
		super();
		this.data = data;
		this.next = next;
	}
	
	public Node(T data) {
		this(data,null);
	}

	public boolean hasNext() {
		return next!=null;
	}

}

2.链表

package myStack;

public class Linkedstack<T> {
	Node<T> head;
	int size;

	public Linkedstack() {
		// TODO Auto-generated constructor stub
	}

	public Linkedstack(Node<T> node) {
		if (head.hasNext()) {
			while (head.next.hasNext()) {
				node.next = head.next.next;
			}
		} else {
			node = head.next;
		}
	}

	Linkedstack(T t) {
		this(new Node(t));
	}

	public boolean isEmpty() {
		return size == 0;
	}

	public int getSize() {
		return size;
	}

	// 返回栈顶元素
	public T peek() {
		T t = null;
		if (!isEmpty()) {
			t = (T) head.next.data;
		}
		return t;
	}

	public void push(T t) {
		Node node=new Node(t);
		node.next=head.next;
		head.next=node;
		size++;
	}

	public T pop() throws IllegalAccessException {
		T t = peek();
		if (!isEmpty()) {
			t=(T) head.next.data;
			head.next=head.next.next;
			return t;
		}else {
			throw new IllegalAccessException("栈空");
		}
		
	}

}

2.1.4重要方法
//1.
public T peek() {
		T t = null;
		if (!isEmpty()) {
			t = (T) head.next.data;
		}
		return t;
	}

//2.
	public void push(T t) {
		Node node=new Node(t);
		node.next=head.next;
		head.next=node;
		size++;
	}

//3.
	public T pop() throws IllegalAccessException {
		T t = peek();
		if (!isEmpty()) {
			t=(T) head.next.data;
			head.next=head.next.next;
			return t;
		}else {
			throw new IllegalAccessException("栈空");
		}
		
	}

5.队列

未完待续,正在持续更新中

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值