首先,我们来说说什么是单向循环链表:
单向循环链表就是单链表的另外一种表现形式,其结构特点是最后一个指针不再是结束标记,而是指向整个链表的第一个结点,从而使单链表形成一个环,就像将一根铁链子首尾连接形成一个铁链环一样。
在单链表中,由于每个结点只存储了向后的指针,到了尾标志就停止了向后链的操作,这样当中的某一结点就无法找到他的前驱结点了,即无法回到之前的结点。这就体现出了单链循环链表的劣势。
说了这么多,我们来看看单向循环链表的实现方法和测试程序吧~~
定义循环链表CycleLinkList
其中头结点为header,尾结点为tail,链表大小为size,类中包含有删除、插入、查找、清空等操作。
package CycleLinkList;
/**
* Created by jiangxs on 17-5-22.
*/
public class CycleLinkList<T> {
//定义一个内部类Node代表链表的节点
private class Node{
private T data;//保存数据
private Node next;//指向下一个节点的引用
//无参构造器
public Node(){}
//初始化全部属性的构造器
public Node(T data,Node next){
this.data = data;
this.next = next;
}
}
private Node header;//保存头结点
private Node tail;//保存尾节点
private int size;//保存已含有的结点数
//创建空链表
public CycleLinkList(){}
//以指定数据元素创建链表,只有一个元素
public CycleLinkList(T element){
header = new Node(element,header);
tail = header;
size++;
}
//返回链表长度
public int getSize(){
return size;
}
//获取指定位置的结点
public Node getNodeByIndex(int index){
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("获取位置超过了链表长度范围");
Node current = header;//从链表表头开始遍历
for (int i = 0;i<size && current.next != null;i++,current = current.next)
if (i == index)
return current;
return null;
}
//获取指定索引处的元素
public T get(int index){
return this.getNodeByIndex(index).data;
}
//按值查找所在位置
public int local(T element){
Node current = header;
for (int i = 0;i < size && current != null;i++,current = current.next)
if (current.data.equals(element))
return i;
return -1;
}
//在尾部插入元素
public void add(T element){
//如果链表为空
if (isEmpty()){
header = new Node(element,header);
tail = header;//空链表中头结点和尾结点相同
}
else {
//创建新结点
Node newNode = new Node(element,null);
//让尾结点指向新结点
tail.next = newNode;
//让新结点指向头结点
newNode.next = header;
//将新结点作为尾结点
tail = newNode;
}
size++;
}
//在头部插入
public void addHeader(T element){
//如果链表为空
if (isEmpty()) {
header = new Node(element,header);
tail = header;
}
else {
//创建新结点
Node newNode = new Node(element, null);
//让新结点指向header
newNode.next = header;
//然后让新结点作为header
header = newNode;
//将尾结点指向头结点
tail.next = header;
}
size++;
}
/**
* 在指定位置插入元素
* @param element 要插入的元素
* @param index 要插入的位置
*/
public void insert(T element,int index){
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("插入位置超出链表范围");
//如果链表为空
if (header == null)
add(element);
else {
//如果插入位置为0
if (index == 0)
addHeader(element);
else {
//获取插入位置的前一个结点
Node prev = getNodeByIndex(index-1);
//让prev指向新的结点,新结点指向原prev结点的下一个结点
prev.next = new Node(element,prev.next);
size++;
}
}
}
/**
* 删除索引处的元素
* @param index
* 输入要删除的位置
*/
public T delete(int index){
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("删除位置超出链表范围");
Node del = null;
//如果删除的是头结点
if (index == 0){
del = header;
header = header.next;
del.next = null;
tail.next = header;
}
//如果删除的是尾结点
else if (index == size-1){
Node prevT = getNodeByIndex(index-1);
del = tail;
tail = prevT;
del.next = null;
tail.next = header;
}
//如果删除的是中间结点
else if (index > 0 && index < size-1){
Node prev = getNodeByIndex(index-1);
del = prev.next;
prev.next = del.next;
del.next = null;
}
size--;
return del.data;
}
//删除最后一个元素
public T remove(){
return delete(size-1);
}
//判断链表是否为空
public boolean isEmpty(){
return size == 0;
}
//清空线性表
public void clear(){
//将头结点和尾结点设为空
header = null;
tail = null;
size = 0;
}
public String toString(){
if (isEmpty())
return "[]";
else {
StringBuilder sb = new StringBuilder("[");
sb.append(header.data+"->").toString();
for (Node current = header.next;current != header;current = current.next)
sb.append(current.data+"->").toString();
int len = sb.length();
return sb.delete(len-2,len).append("]").toString();
}
}
}
测试代码
package CycleLinkList;
/**
* Created by jiangxs on 17-5-22.
*/
public class CycleLinkListTest {
public static void main(String[] args) {
CycleLinkList<String> ll = new CycleLinkList<String>();
//在链表尾添加元素
ll.add("haha");
ll.add("hehe");
ll.add("xixi");
System.out.println("原有循环链表中的元素: ");
System.out.println(ll);
//在链表头插入元素
ll.addHeader("hiahia");
System.out.println("循环链表头结点插入后链表中的元素: ");
System.out.println(ll);
//在循环链表中位置2处插入元素
ll.insert("heihei",2);
System.out.println("循环链表2处插入元素后链表中的元素: ");
System.out.println(ll);
//删除循环链表中位置2的元素
ll.delete(2);
System.out.println("循环链表2处删除元素后链表中的元素: ");
System.out.println(ll);
//删除循环链表中尾结点
ll.remove();
System.out.println("循环链表末尾处删除元素后链表中的元素: ");
System.out.println(ll);
System.out.println("循环链表中元素haha的位置: "+ll.local("haha"));
System.out.println("循环链表中位置1的元素: "+ll.get(1));
System.out.println("循环链表的长度为: "+ll.getSize());
}
}
测试结果
原有循环链表中的元素:
[haha->hehe->xixi]
循环链表头结点插入后链表中的元素:
[hiahia->haha->hehe->xixi]
循环链表2处插入元素后链表中的元素:
[hiahia->haha->heihei->hehe->xixi]
循环链表2处删除元素后链表中的元素:
[hiahia->haha->hehe->xixi]
循环链表末尾处删除元素后链表中的元素:
[hiahia->haha->hehe]
循环链表中元素haha的位置: 1
循环链表中位置1的元素: haha
循环链表的长度为: 3
Process finished with exit code 0
参考:《大话数据结构》