线性表链式存储结构——单向循环链表

单行循环链表

概念:单向,都知道,上一个博客中也介绍了单链表的概念,循环也很好理解,将单链表实现首尾相连。即尾节点的指针域存储的是首节点的地址。

因为循环链表(LoopList)还是属于线性表,因此我们与单链表一样,可以定义一个LoopList类,继续让它实现接口List<E>,并实现当中的方法,与单链表中一样,我们还是一样,继续定义一个内部类Node,并且用户不可访问,只是通过LoopList使用循环链表。下图为单向循环链表。


1、先创建一个内部类Node,并且与之前一样,继续有data域和next指针域。便于链表节点之间的链接。

private class Node {
		E data;// 数据域
		Node next;// 指针域

		public Node() {
			this(null, null);
		}

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

		@Override
        //重写toString方法,以便于输出节点信息。
		public String toString() {
			return data.toString();
		}
	}

2、获取链表的长度。getSize()方法。

    public int getSize() {
		//size为之前定义的size用于存储链表的长度
		return size;
	}

3、判断链表是否为空,这也是比较重要的一步,在删除元素,插入元素等功能时也起着作用。isEmpty();

  public boolean isEmpty() {
		return size == 0 && head == null && rear == null;
	}

 4、接下来就应该给链表中添加元素了,也是有点困难的一步。在单链表中我们设置头节点为虚拟头节点,但是我们在循环链表中,应该注意一下,因为是循环链表,为了之后的尾指针便于和头指针相连,所以我们设置为真实头结点。刚开始时,头节点和尾节点都限制为空。知道有一个元素进来时在移动。

(1)链表为空时,我们插入元素时,应注意,当第一个元素来时,应当将头尾指针都指向这个节点,之后将为指针再指向头指针。

   if (isEmpty()) {//判断是否为空若为空证明时空链表。
	head = n;
	rear = n;
	rear.next = head;
   }

(2)头插法,先将头节点的地址,给这个新结点,然后将该新结点的地址给头指针.最后将尾指针的节点的指针域指向该链表头节点。

   if (index == 0) {// 头插
    n.next = head;
	head = n;
   	rear.next = n;
   }

 (3)尾插法,将新结点的next域指向头节点,然后将尾指针指向的节点的next域指向这个新结点,最后将尾指针指向尾指针的后继。

if (index == size) {// 尾插
	n.next = rear.next;
	rear.next = n;
	rear = rear.next;
}

(4)一般插法,与单链表中的一般插入发一样,不用考虑头尾指针,先通过循环找到待插位置,然后再进行插入。

{
	Node p = head;
	for (int i = 0; i < index - 1; i++) {
		p = p.next;
	}
	n.next = p.next;
	p.next = n;
}

(5)当然,在最后执行完插入后,size要加1.

5、删除元素,remove(int index);

(1) 删除角标合法时,我们要判断删除元素的位置,如果是删除的链表只有一个元素时,直接将头尾指针都指向空就可以了。

if (size == 1) {
	res = head.data;
	head = null;
	rear = null;
}

 (2)删除头结点时,将头指针后移到当前头指针的后继节点,之后将尾指针指向当前头节点。

if (index == 0) {
	res = head.data;
	head = head.next;
	rear.next = head;
}

(3)删除尾结点时,因为没有角标,所以必须用循环找到尾结点的前驱节点p,之后将当前尾指针的后继结点的地址,也就是头节点的地址给p.next,最后将为指针往前移就可以了,就是指向p当前的节点。 

if (index == size - 1) {
	res = rear.data;
	Node p = head;
	while (p.next != rear) {
		p = p.next;
	}
	p.next = rear.next;
	rear = p;
}

 (4)一般删除,通过待删节点的角标,找到待删节点的前驱节点,之后将带删节点的后继节点的地址给当前带删节点的前驱节点,就已经达到删除操作了,当然也可以将删除元素的next置空。不过也不影响。

{
	Node p = head;
	for (int i = 0; i < index - 1; i++) {
		p = p.next;
	}
	Node del = p.next;
	res = del.data;
	p.next = del.next;
	del.next = null;
}

(5)最后将链表的长度减1。 

 6、还有一个clear的功能,就是将头尾指针都置为null;然后将链表长度置为0;

至此,循环链表功能也基本实现了。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值