数据结构线性结构:栈、单向、双向链表

线性结构

一、栈结构
1.栈的定义
在这里插入图片描述

2.实现栈结构

import java.util.Arrays;
import java.util.EmptyStackException;

/**

  • 自定义栈容器
  • @author Lhk

*/
public class MyStack {

private Object[] arr;//存放元素的物理结构

private int stackLength =4;//数组的默认长度

private int size;//记录栈容器的元素个数

private int index=-1;//操作数组下标位置的指针






/**
 * 判断栈容器是否为空
 * @return
 */
public boolean empty(){
	//栈为空返回true,否则返回false
	return this.size==0;
}

/**
 * 获取栈顶元素
 */
@SuppressWarnings("unchecked")
public E pop(){
	//如果栈为空,则抛出异常
	if(this.index==-1){
		throw new EmptyStackException();
	}
	//记录元素个数
	this.size--;
	//否则返回栈顶元素
	return (E)this.arr[index--];
}

/**
 * 向栈容器中添加元素
 * @param e
 * @return
 */
public E push(E e){
	//1.初始化数组
	capacity();
	//2.向数组中添加元素
	this.arr[++index]=e;
	//3.记录元素个素
	this.size++;
	return null;
}

/**
 * 完成数组初始化和数组扩容(以1.5倍容量进行扩容)
 * @param args
 */
private void capacity(){
	//数组初始化
	if(this.arr==null){
		this.arr=new Object[this.stackLength];
	}
	
	//数组扩容
	if(this.size-(this.stackLength-1)>=0){
		this.stackLength=this.stackLength+(this.stackLength>>1);
		this.arr=Arrays.copyOf(this.arr, this.stackLength);
	}
}


public static void main(String[] args) {
	MyStack<String> s=new MyStack<>();
	s.push("a");
	s.push("b");
	s.push("c");
	s.push("d");
	s.push("e");
	s.push("f");
	System.out.println(s.size);
	for(int i=0;i<6;i++){
		System.out.println(s.pop());
	}
	System.out.println(s.empty());
}

}

二、链表结构
1.链表结构的定义

  • 什么是链表
    链表结构是由许多节点构成的,每个节点都包含两部分:
    数据部分:保存该节点的实际数据。
    地址部分:保存的是上一个或下一个节点的地址。
  • 链表分类
    单向链表
    双向链表
    双向循环链表
  • 链表的特点
    在这里插入图片描述

2.单向链表结构

  • 单向链表定义
    单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过从头部开始顺序读取。
    在这里插入图片描述
    自定义一个简单的单向链表结构
    i.创建MyList接口
package CustomStructure;
/**
 * 基于链表结构存取元素的方法API定义
 * @param <E>
 */
public interface MyList<E> {

	void add(E element);
	E get(int index);
	int size();
	E remove(int index);
}

ii.创建单向链表类

/**
 * 基于单向链表实现元素存储的容器
 * @author Lhk
 * @param <E>
 *
 */
public class My_Singly_LinkedList<E> implements MyList<E> {

	/**
	 * 向容器中添加元素
	 */
	@Override
	public void add(E element) {
		// TODO Auto-generated method stub
		
	}
	
	/**
	 * 根据元素位置获取元素
	 */
	@Override
	public E get(int index) {
		// TODO Auto-generated method stub
		return null;
	}
	
	/**
	 * 获取元素个素
	 */
	@Override
	public int size() {
		// TODO Auto-generated method stub
		return 0;
	}

	/**
	 * 根据元素位置删除元素
	 */
	@Override
	public E remove(int index) {
		// TODO Auto-generated method stub
		return null;
	}

	public static void main(String[] args) {
		
	}
}

iii.创建结点类

/**
	 * 定义单向链表的结点对象(内部类)
	 */
	class Node<E>{
		private E item;//存储元素
		private Node next;//存储下一个结点对象的地址
		public Node(E item, Node next) {
			super();
			this.item = item;
			this.next = next;
		}
		
	}

iv.实现各个方法

	/**
	 * 向容器中添加元素
	 */
	@Override
	public void add(E element) {
		//创建结点
		Node<E> node=new Node<>(element, null);
		//找到尾结点
		Node tail=getTail();
		//结点挂接
		if(tail==null){
			this.head=node;
		}else{
			tail.next=node;
		}
		//记录元素个数
		this.size++;
	}
	/**
	 * 找尾结点
	 * @return
	 */
	public Node getTail(){
		//先判断头结点是否为空
		if(this.head==null){
			return null;
		}
		//找尾结点
		Node node;
		node=this.head;
		while(true){
		if(node.next==null)break;
		   	node=node.next;//移动指针,指向下一个结点
		}
		return node;
	}
/**
	 * 根据元素位置获取元素
	 */
	@Override
	public E get(int index) {
		//校验index的合法性(0<index<size)
		this.checkIndex(index);
		//根据位置获取指定结点
		Node<E> node=this.getNode(index);
		//将该结点中的元素放回
		return node.item;
	}
	
	/**
	 * 对Index进行校验
	 */
	private void checkIndex(int index){
		if(!(index>=0 && index<this.size)){
			throw new IndexOutOfBoundsException("Index: "+index+"Size: "+size);
		}
	}
	
	/**
	 * 根据位置获取指定结点
	 */
	@SuppressWarnings("unchecked")
	private Node<E> getNode(int index){
		Node<E> node =this.head;
		for(int i=0;i<index;i++){
			node=node.next;
		}
		return node;
		
	}

	/**
	 * 获取元素个素
	 */
	@Override
	public int size() {
		return this.size;
	}
/**
	 * 根据元素位置删除元素
	 */
	@SuppressWarnings("unchecked")
	@Override
	public E remove(int index) {
		//校验index的合法性(0<index<size)
		checkIndex(index);
		//根据位置找到结点对象
		Node<E>  node=this.getNode(index);
		//获取该结点对象的元素
		E item=node.item;
		//将该结点对象从单向链表中移除
			//判断当前删除的结点是否为头结点
		if(this.head==node){
			this.head=node.next;
		}else{
			//从头找到index位置的前一个结点
			Node<E> temp=this.head;
			for(int i=0;i<index-1;i++){
				temp=temp.next;
			}
			temp.next=node.next;
		}
		node.next=null;
		//记录元素个数
		this.size--;
		//将该元素返回
		return item;
	}

	public static void main(String[] args) {
		My_Singly_LinkedList<String> msl=new My_Singly_LinkedList<>();
		msl.add("TheMutents");
		msl.add("qq");
		msl.add("is");
		msl.add("212792772");
		System.out.println(msl.size());
		System.out.println(msl.remove(2));
		for(int i=0;i<msl.size();i++){
			System.out.println(msl.get(i));
		}
	}

完整代码:

/**
 * 基于单向链表实现元素存储的容器
 * @author TheMutents
 * @param <E>
 *
 */
public class My_Singly_LinkedList<E> implements MyList<E> {

	/**
	 * 定义单向链表的结点对象(内部类)
	 */
	@SuppressWarnings("hiding")
	class Node<E>{
		private E item;//存储元素
		@SuppressWarnings("rawtypes")
		private Node next;//存储下一个结点对象的地址
		@SuppressWarnings("rawtypes")
		public Node(E item, Node next) {
			super();
			this.item = item;
			this.next = next;
		}
		
	}
	
	@SuppressWarnings("rawtypes")
	private Node head;//存放链表的头结点
	private int size;//记录元素个数
	
	/**
	 * 向容器中添加元素
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public void add(E element) {
		//创建结点
		Node<E> node=new Node<>(element, null);
		//找到尾结点
		Node tail=getTail();
		//结点挂接
		if(tail==null){
			this.head=node;
		}else{
			tail.next=node;
		}
		//记录元素个数
		this.size++;
	}
	/**
	 * 找尾结点
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	private Node getTail(){
		//先判断头结点是否为空
		if(this.head==null){
			return null;
		}
		//找尾结点
		Node node=this.head;
		while(true){
		if(node.next==null)break;
		   	node=node.next;//移动指针,指向下一个结点
		}
		return node;
	}
	
	/**
	 * 根据元素位置获取元素
	 */
	@Override
	public E get(int index) {
		//校验index的合法性(0<index<size)
		this.checkIndex(index);
		//根据位置获取指定结点
		Node<E> node=this.getNode(index);
		//将该结点中的元素放回
		return node.item;
	}
	
	/**
	 * 对Index进行校验
	 */
	private void checkIndex(int index){
		if(!(index>=0 && index<this.size)){
			throw new IndexOutOfBoundsException("Index: "+index+"Size: "+size);
		}
	}
	
	/**
	 * 根据位置获取指定结点
	 */
	@SuppressWarnings("unchecked")
	private Node<E> getNode(int index){
		Node<E> node =this.head;
		for(int i=0;i<index;i++){
			node=node.next;
		}
		return node;
		
	}
	
	
	/**
	 * 获取元素个素
	 */
	@Override
	public int size() {
		return this.size;
	}

	/**
	 * 根据元素位置删除元素
	 */
	@SuppressWarnings("unchecked")
	@Override
	public E remove(int index) {
		//校验index的合法性(0<index<size)
		checkIndex(index);
		//根据位置找到结点对象
		Node<E>  node=this.getNode(index);
		//获取该结点对象的元素
		E item=node.item;
		//将该结点对象从单向链表中移除
			//判断当前删除的结点是否为头结点
		if(this.head==node){
			this.head=node.next;
		}else{
			//从头找到index位置的前一个结点
			Node<E> temp=this.head;
			for(int i=0;i<index-1;i++){
				temp=temp.next;
			}
			temp.next=node.next;
		}
		node.next=null;
		//记录元素个数
		this.size--;
		//将该元素返回
		return item;
	}

	public static void main(String[] args) {
		My_Singly_LinkedList<String> msl=new My_Singly_LinkedList<>();
		msl.add("TheMutents");
		msl.add("qq");
		msl.add("is");
		msl.add("212792772");
		System.out.println(msl.size());
		System.out.println(msl.remove(2));
		for(int i=0;i<msl.size();i++){
			System.out.println(msl.get(i));
		}
	}
}

3.双向链表结构

  • 双向链表的定义
    在这里插入图片描述
  • 实现自定义双向链表
    i.创建双向链表类
/**
 * 基于双向链表存储结构存储元素的容器
 * @author Lhk
 *
 * @param <E>
 */
public class My_Doublly_LinkedList<E> implements MyList<E> {

	/**
	 * 向容器中添加元素
	 */
	@Override
	public void add(E element) {
		// TODO Auto-generated method stub
		
	}

	/**
	 * 根据指定位置获取元素
	 */
	@Override
	public E get(int index) {
		// TODO Auto-generated method stub
		return null;
	}

	/**
	 * 获取容器中元素个数
	 */
	@Override
	public int size() {
		// TODO Auto-generated method stub
		return 0;
	}

	/**
	 * 根据指定位置删除元素
	 */
	@Override
	public E remove(int index) {
		// TODO Auto-generated method stub
		return null;
	}

	public static void main(String[] args) {
		
	}
}

ii.创建结点类

class Node<E>{
		private E item;//存储元素
		private Node prve;//记录上一个结点对象
		private Node next;//记录下一个结点对象
		
		public Node(E item, Node prve, Node next) {
			super();
			this.item = item;
			this.prve = prve;
			this.next = next;
		}
		
		
	} 

iii.实现各个方法

/**
	 * 向容器中添加元素
	 */
	@Override
	public void add(E element) {
		this.linkedLast(element);
		
	}
	
	/**
	 * 将结点对象添加到双向链表的尾部
	 */
	private void linkedLast(E element){
		//获取尾结点
		Node tail=this.tail;
		//创建一个新结点
		Node<E> node=new Node<>( tail,element, null);
		//将新结点定义成尾结点,如果尾结点为空,则把新结点定义成头结点和尾结点
		this.tail=node;
		if(tail==null){
			this.head=node;
		}else{
			tail.next=node;
		}
		//更新元素个数
		this.size++;
	}

	/**
	 * 根据指定位置获取元素
	 */
	@Override
	public E get(int index) {
		// 对index进行校验
		checkIndex(index);
		//根据位置获取指定结点对象
		Node<E> node=getNode(index);
		//返回指定结点元素
		return node.item;
	}

	/**
	 * 检验index的合法性
	 */
	private void checkIndex(int index){
		if(!(index>=0&&index<this.size)){
			throw new IndexOutOfBoundsException("index: "+index+"size: "+this.size);
		}
	}
	
	/**
	 * 根据位置获取指定结点对象
	 */
	private Node getNode(int index){
		//判断当前位置距离头结点和尾结点那个更近
		if(index<(this.size>>1)){
			Node node=this.head;
			for(int i=0;i<index;i++){
				node=node.next;
			}
			return node;
			}else{
				Node node=this.tail;
				for(int i=this.size-1;i>index;i--){
					node=node.prve;
				}
				return node;
			}
			
	}
/**
	 * 根据指定位置删除元素
	 */
	@Override
	public E remove(int index) {
		//校验index的合法性
		checkIndex(index);
		//获取指定位置结点
		Node<E> node=this.getNode(index);
		//获取当前结点元素值
		E item=node.item;
		//判断当前结点是否为头结点
		if(node.prve==null){
			this.head=node.next;
		}else{
			//完成当前结点的直接前驱与直接后继的挂接
			node.prve.next=node.next;
		}
		//判断当前结点是否为尾结点
		if(node.next==null){
			this.tail=node.prve;
		}else{
			//完成当前结点的直接后继与直接前驱的挂接
			node.next.prve=node.prve;
		}
		//当前结点断掉与它直接后继的连接
		node.next=null;
		//当前结点断掉与它直接前驱的连接
		node.prve=null;
		//元素值置位null,加快回收
		node.item=null;
		//记录元素个数
		this.size--;
		//返回要删除结点的元素值
		return item;
		
	}
/**
	 * 获取容器中元素个数
	 */
	@Override
	public int size() {
		return this.size;
	}

public static void main(String[] args) {
		MyList<String> mlist=new My_Doublly_LinkedList<>();
		mlist.add("a");
		mlist.add("b");
		mlist.add("c");
		mlist.add("d");
		System.out.println(mlist.size());
		for(int i=0;i<mlist.size();i++){
			System.out.println(mlist.get(i));
		}
		System.out.println("删除元素:"+mlist.remove(0));
		for(int i=0;i<mlist.size();i++){
			System.out.println(mlist.get(i));
		}
		
	}
	/**
	 * 将结点对象添加到双向链表的头部
	 */
	public void addFirst(E element) {
		this.linkedFirst(element);
		
	}
	
	/**
	 * 将结点对象添加到双向链表的头部
	 */
	private void linkedFirst(E element){
		//获取到头结点对象
		Node head=this.head;
		//实例化一个新的结点对象
		Node<E> node=new Node<>(null, element, head);
		//将新结点定义为头结点
		this.head=node;
		//判断该链表当前是否有结点,如果没有,则新结点既是头结点有事尾结点
		if(head==null){
			this.tail=node;
		}else{
			head.prve=node;
		}
		//记录元素个数
		this.size++;
	}
/**
	 * 双向链表的尾部添加元素(非接口方法)
	 */
	public void addLast(E element) {
		this.linkedLast(element);
		
	}

完整代码:

package CustomStructure;
/**
 * 基于双向链表存储结构存储元素的容器
 * @author TheMutents
 *
 * @param <E>
 */
public class My_Doublly_LinkedList<E> implements MyList<E> {
	/**
	 * 定义双向链表结点对象
	 * @author Lhk
	 *
	 * @param <E>
	 */
	@SuppressWarnings("hiding")
	class Node<E>{
		private E item;//存储元素
		private Node prve;//记录上一个结点对象
		private Node next;//记录下一个结点对象
		
		public Node( Node prve,E item, Node next) {
			super();
			this.item = item;
			this.prve = prve;
			this.next = next;
		}
	} 
	
	private Node head;//记录头结点
	private Node tail;//记录尾结点
	private int size;

	/**
	 * 向容器中添加元素
	 */
	@Override
	public void add(E element) {
		this.linkedLast(element);
		
	}
	
	/**
	 * 双向链表的头部添加元素(非接口方法)
	 */
	public void addFirst(E element) {
		this.linkedFirst(element);
		
	}
	
	/**
	 * 双向链表的尾部添加元素(非接口方法)
	 */
	public void addLast(E element) {
		this.linkedLast(element);
		
	}
	
	/**
	 * 将结点对象添加到双向链表的头部
	 */
	private void linkedFirst(E element){
		//获取到头结点对象
		Node head=this.head;
		//实例化一个新的结点对象
		Node<E> node=new Node<>(null, element, head);
		//将新结点定义为头结点
		this.head=node;
		//判断该链表当前是否有结点,如果没有,则新结点既是头结点有事尾结点
		if(head==null){
			this.tail=node;
		}else{
			head.prve=node;
		}
		//记录元素个数
		this.size++;
	}
	
	
	/**
	 * 将结点对象添加到双向链表的尾部
	 */
	private void linkedLast(E element){
		//获取尾结点
		Node tail=this.tail;
		//创建一个新结点
		Node<E> node=new Node<>( tail,element, null);
		//将新结点定义成尾结点,如果尾结点为空,则把新结点定义成头结点和尾结点
		this.tail=node;
		if(tail==null){
			this.head=node;
		}else{
			tail.next=node;
		}
		//更新元素个数
		this.size++;
	}

	/**
	 * 根据指定位置获取元素
	 */
	@Override
	public E get(int index) {
		// 对index进行校验
		checkIndex(index);
		//根据位置获取指定结点对象
		Node<E> node=getNode(index);
		//返回指定结点元素
		return node.item;
	}

	/**
	 * 检验index的合法性
	 */
	private void checkIndex(int index){
		if(!(index>=0&&index<this.size)){
			throw new IndexOutOfBoundsException("index: "+index+"size: "+this.size);
		}
	}
	
	/**
	 * 根据位置获取指定结点对象
	 */
	private Node getNode(int index){
		//判断当前位置距离头结点和尾结点那个更近
		if(index<(this.size>>1)){
			Node node=this.head;
			for(int i=0;i<index;i++){
				node=node.next;
			}
			return node;
			}else{
				Node node=this.tail;
				for(int i=this.size-1;i>index;i--){
					node=node.prve;
				}
				return node;
			}
			
	}
	
	/**
	 * 获取容器中元素个数
	 */
	@Override
	public int size() {
		return this.size;
	}

	/**
	 * 根据指定位置删除元素
	 */
	@Override
	public E remove(int index) {
		//校验index的合法性
		checkIndex(index);
		//获取指定位置结点
		Node<E> node=this.getNode(index);
		//获取当前结点元素值
		E item=node.item;
		//判断当前结点是否为头结点
		if(node.prve==null){
			this.head=node.next;
		}else{
			//完成当前结点的直接前驱与直接后继的挂接
			node.prve.next=node.next;
		}
		//判断当前结点是否为尾结点
		if(node.next==null){
			this.tail=node.prve;
		}else{
			//完成当前结点的直接后继与直接前驱的挂接
			node.next.prve=node.prve;
		}
		//当前结点断掉与它直接后继的连接
		node.next=null;
		//当前结点断掉与它直接前驱的连接
		node.prve=null;
		//元素值置位null,加快回收
		node.item=null;
		//记录元素个数
		this.size--;
		//返回要删除结点的元素值
		return item;
		
	}

	public static void main(String[] args) {
		MyList<String> mlist=new My_Doublly_LinkedList<>();
		mlist.add("a");
		mlist.add("b");
		mlist.add("c");
		mlist.add("d");
		System.out.println(mlist.size());
		for(int i=0;i<mlist.size();i++){
			System.out.println(mlist.get(i));
		}
		System.out.println("删除元素:"+mlist.remove(0));
		for(int i=0;i<mlist.size();i++){
			System.out.println(mlist.get(i));
		}
		
		System.out.println("------测试非接口方法------");
		My_Doublly_LinkedList<String> mdlist=new My_Doublly_LinkedList<>();
		mdlist.add("B");
		mdlist.addFirst("A");
		mdlist.addLast("C");
		mdlist.addFirst("A");
		for(int i=0;i<mlist.size();i++){
			System.out.println(mdlist.get(i));
		}
		
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

The Mutents

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值