数据结构之循环链表结构

循环链表结构是什么?
你面前有一扇们,门上面有个数字0,打开门,进去,你又看到一扇门,门上面写着1,就这样你开了十扇门,你抬头一看,门上数字写着9,你打开了写着9的这扇门,里面还有一扇门,里面这扇门赫然写着数字0,你又回到了原点。可是你一直朝着一个方向 在走呀,难道这是灵异事件,不对,恭喜你发现了程序的美丽。有一天早晨,你起床刷牙时候忽然想看看牙齿,啊~ 你张开口,发现口里面还有一个你,同样张着嘴,发出啊~ 的声音,你嘴里的你的嘴里还有一个你在张着嘴发着啊~ 你瞬间惊醒了,原来是在做梦,想明白了这个,循环链表结构差不多就该明白了吧。如果你还不明白,看着你面前的东西,对,就是面前任何的东西,你就开始想,我在看着这个东西,我在看着看着这个东西的我,我在看着看着这个东西的看着这个东西的我。。。 明白了吧。
循环链表结构?
命运之蛇咬住了自己的尾巴,世界开启了一个新纪元。
命运之蛇吃掉了自己的尾巴,世界的寿命变短了。
命运之舌长大了,世界的寿命也因此变长了。
命运之蛇吃掉了自己,世界毁灭了。

开始单向循环链表结构的构建。
底层实现:对节点类进行操作。
单向循环链表实现了List接口

    public interface List<E> {
    	public int getSize();
    	public boolean isEmpty();
    	public void add(int index,E e);
    	//表头添加元素
    	public void addFirst(E e);
    	//表尾添加元素
    	public void addLast(E e);
    	
    	//在表中根据指定角标获取元素,指定角标大于0小于角标的个数size
    	public E get(int index);
    	
    	//获取表头元素 返回值为表头元素 0
    	public E getFirst();
    	
    	//获取表尾元素  返回值为表尾元素   size-1
    	public E getLast();
    	
    	//修改线性表中指定index处的元素为E  没有返回值
    	public void set(int index,E e);
    	
    	//判断线性表中是否包含指定元素e  参数为E   返回值为boolean 
    	public boolean contains(E e);
    	
    	//在线性表中获取元素角标  从前往后找   参数为E  返回值为int   返回数据角标
    	public int find(E e);
    	
    	//在线性表中  根据指定角标 删除元素  并返回该元素    角标范围为:0至size-1
    	public E remove(int index);
    	
    	//在线性表中 删除表头元素 返回表头元素
    	public E removeFirst();
    	
    	//在线性表中 删除表尾元素  返回删除元素	
    	public E removeLast();
    	
    	//在线性表中根据元素删除指定元素  
    	public void removeElement(E e);
    
    	//清空线性表  无返回值  无参数
    	public void clear();
    	
    	public boolean equals(Object obj);
	
接着看实现:

public class LoopSingle001<E> implements List<E> {
	// 首先构建一个节点类
	private class Node {
		private E data;
		private Node next;

		// 初始化
		public Node() {
			this(null, null);// 代表调用当前对象两个参数的构造方法
		}

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

	}

	// 节点构造好了,需要对头和为进行标记
	private Node head;
	private Node rear;
	private int size;

	// 对操作工具进行实例化
	public LoopSingle001() {
		head = null;
		rear = null;
		size = 0;
	}

	public int getSize() {
		return size;
	}

	public boolean isEmpty() {
		return head == null && rear == null && size == 0;
		// 当头元素等于空 尾元素等于空 元素个数等于0 则链表为空
	}

	// 根据下标插入元素
	public void add(int index, E e) {
		// 对index进行判断
		if (index < 0 || index > size) {
			throw new IllegalArgumentException("插入角标非法!");
		}
		Node n = new Node(e, null); // 创建一个新节点,并让它的下一跳指向空,便于头插和尾插
		// 非空判断
		if (isEmpty()) {
			// 当元素为空时,创建一个指针指向空的新元素		
			head = n; // 头指向新元素
			rear = n; // 尾指向新元素
			rear.next = head; // 尾的下一个指向头head
			
			size = 1;
		} else { // 当元素不为空时,

			if (index == 0) {
				// 当index==0时插哪里?插头
				// 创建一个新节点用来保存e				
				n.next=head;
				head = n;
				rear.next = head;
				size++;
			
			} else if (index == size) {
				// 当index==size;往size当前位置插入,也就是尾节点后移,往尾节点的原来位置插入
				// 先获取当前尾节点的前一个节点 创建一个临时节点对象用来进行遍历
				
//				Node p = head;      //没有意义
//				// 同理,获取index处的前一个节点       
//				for (int i = 0; i < index-2; i++) {  //假设你有5个元素,你从0开始遍历,循环第4遍的时候就获得了5  你要插入5 
//					p = p.next;
//				}
//				n.next=p.next;
//				p.next=n;
//				size++;
				
				//如果插入位置index==size  那么插向尾部的下一个节点
				rear.next=n;
				n.next=head;
				rear=n;
				size++;
			} 
				else {
				Node p = head;
				// 同理,获取index处的前一个节点
				for (int i = 0; i < index-1; i++) {
					p = p.next;
				}
				p.next=n;
				n.next=p.next;
				size++;
			}
		}
	}

	// 表头添加元素
	public void addFirst(E e) {
		add(0, e);

	}

	// 表尾添加元素
	public void addLast(E e) {
		add(size, e);
	}

	// 在表中根据指定角标获取元素,指定角标大于0小于角标的个数size
	public E get(int index) {
		if (index < 0 || index > size) {
			throw new IllegalArgumentException("角标非法!");
		}
		// 根据index获取节点,怎么获取?从头结点0开始向后遍历,直到index处,获取。
		if (index == 0)
			return head.data;
		if (index == size)
			return rear.data;
		Node p = head;
		for (int i = 0; i < index; i++) {     //因为我们这里有个虚拟的下标是从0开始的所以这里不减1
			p = p.next;
		}
		return p.data;

	}

	// 获取表头元素 返回值为表头元素 0
	public E getFirst() {
		return get(0);
	}

	// 获取表尾元素 返回值为表尾元素 size-1
	public E getLast() {
		return get(size);
	}

	// 修改线性表中指定index处的元素为E 没有返回值
	public void set(int index, E e) {
		if (index < 0 || index > size) {
			throw new IllegalArgumentException("角标非法!");
		}
		Node p = head;
		if (index == 1) {   //当index=1 获取第0个节点 
			p.data = e;
		}
		if (index == size) {
			rear.data = e;
		}
		for (int i = 0; i <= index; i++) {
			p = p.next;
		}
		p.data = e;

	}

	// 判断线性表中是否包含指定元素e 参数为E 返回值为boolean
	public boolean contains(E e) {
		if (find(e) != -1)
			return true;
		return false;

	}

	// 在线性表中获取元素角标 从前往后找 参数为E 返回值为int 返回数据角标
	public int find(E e) {
		Node p = head;
		if(p.data==e){
			return 0;
		}else if(p.data==rear.data){
			return size;
		}else{
			for (int i = 0; i < size; i++) {
				p=p.next;
				if (p.data == e) return i;					
			}	
		}
		return -1;
	}

	// 在线性表中 根据指定角标 删除元素 并返回该元素 角标范围为:0至size-1
	public E remove(int index) {
		if (index < 0 || index > size) {
			throw new IllegalArgumentException("角标非法!");
		}
		E e = null;
		Node p = head;
		if (index == 0) {
			e = head.data;
			head=p.next;
			rear.next = p.next;
			size--;
			return e;
		} else if (index == size) {
			for (int i = 0; i < index-2; i++) {   //这里为什么要减2  因为减1获取到的是最后一个值, 第一次循环过后,p获取的是虚拟下标为1的值,0直接略过了
				p = p.next;
			}
			e = rear.data;
			p.next = rear.next;
			rear=p;
			size--;
			return e;

		} else {

			for (int i = 0; i < index-2; i++) {  //获取index的前一个元素  这里从虚拟下标0开始,获取第index个元素,先获取第index前一个元素,循环当中,循环次数要成index-2
				p = p.next;
			}
			
			e = p.next.data;
			p.next = p.next.next;
			size--;
			return e;
		}
	}

	// 在线性表中 删除表头元素 返回表头元素
	public E removeFirst() {
		return remove(0);
	}

	// 在线性表中 删除表尾元素 返回删除元素
	public E removeLast() {
		return remove(size);
	}

	// 在线性表中根据元素删除指定元素
	public void removeElement(E e) {
		int index = find(e);
		remove(index+2);  //这里加一是因为,我们获取的是元素下标是从0开始计算,而我们删除时,是从1开始计算
	}

	// 清空线性表 无返回值 无参数
	public void clear() {
		head = null;
		rear = null;
		size = 0;

	}

	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("LoopSingle:size=" + getSize() + "\n");
		if (isEmpty()) {
			sb.append("[]");
		} else {
			sb.append('[');
			Node p = head;
			while (true) {
				sb.append(p.data);
				if (p.next == head) {
					sb.append(']');
					break;
				} else {
					sb.append(',');
				}
				p = p.next;
			}
		}
		return sb.toString();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值