`
zhouYunan2010
  • 浏览: 206084 次
  • 性别: Icon_minigender_1
  • 来自: 湖南
社区版块
存档分类

用动态数组模拟双向循环链表

阅读更多
简单来说其实使用数组模拟LinkedList。同LinkedList的操作基本相似。
基本原理为:数组存放Entry对象,包含数据部分,指针部分(数组下标)
添加,删除基本操作改变指针。数组包含两个链表,一个备用链表(空数据,仅含指针)与
实际存放数据的链表(即保存存入的数)。添加先从备用链表中获取一个空闲节点,
移除把节点重新放入备用链表等待获取。采用ArrayList的数组自动扩张的方法。
具体代码如下:
package com.utils;

import java.util.AbstractSequentialList;
import java.util.Arrays;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;




/**
 * 用数组模拟双向循环列表
 */
public class ArrayLinkedList<E> extends AbstractSequentialList<E> implements 
		List<E>{
	
	//空闲链表头结点,索引为0的位置设置头结点
	private transient Entry<E> freeHeader;	
	//实际链表头结点,索引为1的位置设置头结点
	private transient Entry<E> header;
	private transient int size = 0;		//数组中存储的Entry对象个数
	
	private transient Object[] data;	//Object数组,因为java不支持泛型数组,即Entry<E>[] data = new Entry<E>[10] //error
										//遍历时进行强制类型转换即可
	/**
	 * 构造方法一,初始化化数组 
	 */
	public ArrayLinkedList(int initialCapacity) {
		super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        initArray(initialCapacity);
	}
	
	/**
	 * 构造方法二,构造含有指定集合c中所有元素的链表
	 * 具体见addAll方法
	 */
	public ArrayLinkedList(Collection<? extends E> c) {
		this();
		addAll(c);
	}
	
	/**
	 * 默认数组长度
	 */
	public ArrayLinkedList(){
		this(10);
	}
	
	/**
	 * 初始化数组.
	 * 除header,其他都是备用链表的元素
	 * 实际链表此时为空。数据项都为空
	 */
	private void initArray(int initialCapacity) {
		data = new Object[initialCapacity];
		for(int i = 0 ;i < data.length;i++){
			if(freeHeader==null){
				freeHeader = new Entry<E>(null, i, i+2, data.length-1);
				data[i] = freeHeader;
				continue;
			}
			if(header == null){
				header = new Entry<E>(null, i, i, i);	//初始实际链表头结点,此链表为空
				data[i] = header;
				continue;
			}
			Entry<E> e = new Entry<E>(null, i, 
					i+1==data.length ? 0 : i+1, i-1 == 1 ? 0 : i-1);
			data[i] = e;
		}
	}
	
	/**
	 * 获取一个备用链表的节点
	 * */
	public int getFreeNode(){
		int i = freeHeader.next;
		if(i > 0 ){
			Entry e = (Entry)data[i];
			freeHeader.next = e.next;
			((Entry)data[e.next]).pre = freeHeader.cur;
		}
		return i;
	}
	
	/**
	 * 将空闲节点回收到备用链表
	 * */
	public void free(Entry<E> e){
		e.next  = freeHeader.next;
		e.pre = freeHeader.cur;
		freeHeader.next = e.cur;
		e.element = null;
	}
	
	public void ensureCapacity(int minCapacity) {
		modCount++;
		int oldCapacity = data.length;
		if (minCapacity > oldCapacity) {
			int newCapacity = (oldCapacity * 3) / 2 + 1;
			if (newCapacity < minCapacity)
				newCapacity = minCapacity;
			data = Arrays.copyOf(data, newCapacity);
			//初始化增加的节点
			for(int i = oldCapacity; i < newCapacity;i++){
				Entry<E> e = new Entry<E>(null, i, 
						i+1==data.length ? 0 : i+1, i-1 == 1 ? 0 : i-1);
				data[i] = e;
				//修改备用头结点
				freeHeader.pre = newCapacity - 1;
				freeHeader.next = oldCapacity;
			}
		}
	}

	public E getFirst(){
		if(size == 0)
			throw new NoSuchElementException();
		return ((Entry<E>)data[header.next]).element;
	}
	
	public E getLast(){
		if(size == 0)
			throw new NoSuchElementException();
		return  ((Entry<E>)data[header.pre]).element;
	}
	
	/**
	 * 移除第一个元素,具体见remove()方法
	 */
	public E removeFirst() {
		return remove((Entry<E>)data[header.next]);
	}

	/**
	 * 移除最后一个元素
	 */
	public E removeLast() {
		return remove((Entry<E>)data[header.pre]);
	}
	
	/**
	 * 
	 * 在链表开始位置添加一个元素
	 * 详情见addBefore()
	 */
	public void addFirst(E e) {
		addBefore(e, (Entry<E>)data[header.next]);
	}

	/**
	 * 在链表最后位置添加一个元素
	 * 详情见addBefore()
	 */
	public void addLast(E e) {
		addBefore(e, header);
	}
	
	/**
	 * 查看链表是否包含元素o
	 * 详细见indexOf()方法
	 */
	public boolean contains(Object o) {
		return indexOf(o) != -1;
	}
	
	/**
	 * 
	 * 返回o第一次出现的位置,如果在List中找不到o返回-1
	 */
	public int indexOf(Object o) {
		int index = 0;	//链表的索引也是从0开始
		if (o == null) {
			for (Entry e = (Entry)data[header.next]; e != header; e = (Entry)data[e.next]) {	//从头结点开始,依次遍历
				if (e.element == null)
					return index;
				index++;
			}
		} else {
			for (Entry e = (Entry)data[header.next]; e != header; e = (Entry)data[e.next]) {
				if (o.equals(e.element))
					return index;
				index++;
			}
		}
		return -1;
	}
	
	/**
	 * 双向循环链表,从后面开始遍历即可
	 */
	public int lastIndexOf(Object o) {
		int index = size;
		if (o == null) {
			for (Entry e = (Entry)data[header.pre]; e != header; e = (Entry)data[e.pre]) {
				index--;
				if (e.element == null)
					return index;
			}
		} else {
			for (Entry e = (Entry)data[header.pre]; e != header; e = e = (Entry)data[e.pre]) {
				index--;
				if (o.equals(e.element))
					return index;
			}
		}
		return -1;
	}

	/**
	 * 跟addLast()方法类似,添加成功返回true
	 */
	public boolean add(E e) {
		addBefore(e, header);
		return true;
	}
	
	/**
	 * 假如链表中含有一个或多个o对象,移除第一次出现的o
	 * 如果找不到o返回false
	 */
	public boolean remove(Object o) {
		if (o == null) {
			for (Entry<E> e = (Entry<E>)data[header.next]; e != header; e = (Entry<E>)data[e.next]) {	//从第一个元素开始遍历,没一个Entry对象都包含它下一个元素的信息
				if (e.element == null) {
					remove(e);
					return true;
				}
			}
		} else {
			for (Entry<E> e = (Entry<E>)data[header.next]; e != header; e = (Entry<E>)data[e.next]) {
				if (o.equals(e.element)) {
					remove(e);
					return true;
				}
			}
		}
		return false;
	}
	
	/**
	 * 
	 * 把c中所有元素按顺序添加到链表尾部
	 */
	public boolean addAll(Collection<? extends E> c) {
		return addAll(size, c);
	}
	
	/**
	 * 
	 * 在指定位置按顺序添加c中所有元素带List中
	 * 
	 */
	public boolean addAll(int index, Collection<? extends E> c) {
		if (index < 0 || index > size)	//检查是否越界,=size表示添加到最后
			throw new IndexOutOfBoundsException("Index: " + index + ", Size: "
					+ size);
		Object[] a = c.toArray();
		int numNew = a.length;
		if (numNew == 0)
			return false;
		ensureCapacity(size + numNew + 2);

		Entry<E> successor = (index == size ? header : entry(index));
		Entry<E> predecessor = (Entry<E>)data[successor.pre];
		for (int i = 0; i < numNew; i++) {	//这里不难,画一个图就出来了,主要是初始化c和修改指针
			//暂时使其next为successor,因为e会赋给前驱,而每次遍历都要修改其前驱的next
			int node = getFreeNode();
			Entry<E> e = (Entry<E>)data[node];
			e.next = successor.cur;
			e.pre = predecessor.cur;
			e.element = (E)a[i];
			predecessor.next = e.cur;   //重新设置前驱的next指针
			predecessor = e;	//让e变为前驱
		}
		successor.pre = predecessor.cur;	//successor的前驱为c中最后一个元素的引用

		size += numNew;		//长度加
		return true;
	}
	
	/**
	 * 移除链表中所有元素
	 */
	public void clear() {
		Entry<E> e = (Entry<E>)data[header.next];
		while (e != header) {	//表示不是只有一个头结点的空链表
			Entry<E> next = (Entry<E>)data[e.next];
			free(e);
			e = next;
		}
		header.next = header.pre = header.cur = 1;	//初始头结点
		size = 0;
		modCount++;
	}
	
	/**
	 * 返回指定位置的元素时
	 */
	public E get(int index) {
		return entry(index).element;
	}

	/**
	 * 设置指定位置的元素
	 */
	public E set(int index, E element) {
		Entry<E> e = entry(index);
		E oldVal = e.element;
		e.element = element;
		return oldVal;
	}
	
	/**
	 * 
	 * 把指定元素添加到指定位置,需先定位到此位置的节点
	 * 详情见addBefore()
	 */
	public void add(int index, E element) {
		addBefore(element, (index == size ? header : entry(index)));
	}

	/**
	 * 移除指定位置的元素
	 */
	public E remove(int index) {
		return remove(entry(index));
	}
	
	/**
	 * 
	 * 返回指定索引位置的Entry对象,需要依次遍历得到。
	 * 这里稍做了一下优化,如果index < size/2 从前面开始遍历
	 * 如果index >= size/2 从后面开始遍历
	 */
	private Entry<E> entry(int index) {
		if (index < 0 || index >= size)	//index在0(包含)到size(不包含)之间,索引从0开始
			throw new IndexOutOfBoundsException("Index: " + index + ", Size: "
					+ size);
		Entry<E> e = header;
		if (index < (size >> 1)) {
			for (int i = 0; i <= index; i++)
				e = (Entry<E>)data[e.next];	//依次调用e.next才能得到,需调用index+1次,因为它是从头结点开始的
		} else {
			for (int i = size; i > index; i--)
				e = (Entry<E>)data[e.pre]; //依次调用e.previous才能得到
		}
		return e;
	}
	
	
	private Entry<E> addBefore(E e,Entry<E> entry){
		ensureCapacity(size + 1 + 2);
		int node = getFreeNode();
		Entry<E> newEntry = (Entry<E>)data[node];
		newEntry.element = e;
		newEntry.cur = node;
		newEntry.pre = entry.pre;
		newEntry.next = entry.cur;
		
		((Entry<E>)data[newEntry.pre]).next = node;
		((Entry<E>)data[newEntry.next]).pre = node;
		size++;
		return newEntry;
	}
	
	private E remove(Entry<E> e){
		if(e == header)
			throw new NoSuchElementException();
		E result = e.element;
		//改变实际链表的节点指针
		((Entry<E>)data[e.pre]).next = e.next;
		((Entry<E>)data[e.next]).pre = e.pre;
		free(e);
		size--;		//size--
		modCount++;
		return result;
	}
	
	@Override
	public ListIterator<E> listIterator(int index) {
		return new ListItr(index);
	}

	@Override
	public int size() {
		// TODO Auto-generated method stub
		return size;
	}
	

	private static class Entry<E>{
		E element;
		int next;
		int pre;
		int cur;
		
		Entry(E element,int cur,int next,int pre){
			this.element = element;
			this.next = next;
			this.pre = pre;
			this.cur = cur;
		}
		public String toString(){
			return "element:"+ element +" cur:"+cur+" next:"+next+" pre:"+pre;
		}
	}
	

	private class ListItr implements ListIterator<E> {
		private Entry<E> lastReturned = header;		//上一次调用next或previous返回的元素,没有调用next则为头结点
		private Entry<E> next;	//下一次调用next方法返回的元素
		private int nextIndex;	//下一次调用next返回的元素的索引
		private int expectedModCount = modCount;	//用来检测遍历过程中是否产生了并发操作

		ListItr(int index) {	//构造器,是迭代器定位到index位置,要返回index位置的元素需调用一次next()方法时
			if (index < 0 || index > size)	
				throw new IndexOutOfBoundsException("Index: " + index
						+ ", Size: " + size);
			if (index < (size >> 1)) {	//从前面开始遍历
				next = (Entry<E>)data[header.next];	 //这是index为0的元素
				for (nextIndex = 0; nextIndex < index; nextIndex++)
					next = (Entry<E>)data[next.next];	//最终next为第index个元素,index从0开始
			} else {		//从后面开始遍历
				next = header;
				for (nextIndex = size; nextIndex > index; nextIndex--)
					next = (Entry<E>)data[next.pre];	//最终next为第index个元素,index从0开始
			}
		}

		public boolean hasNext() {	//size位置可没有元素
			return nextIndex != size;
		}

		public E next() {
			checkForComodification();
			if (nextIndex == size)
				throw new NoSuchElementException();

			lastReturned = next;
			next = (Entry<E>)data[next.next];	//这里与ArrayList中的cursor何其相似
			nextIndex++;
			return lastReturned.element;
		}

		public boolean hasPrevious() {
			return nextIndex != 0;
		}

		public E previous() {
			if (nextIndex == 0)
				throw new NoSuchElementException();

			lastReturned = next = (Entry<E>)data[next.pre];
			nextIndex--;
			checkForComodification();
			return lastReturned.element;
		}

		public int nextIndex() {	//返回下一次调用next返回的元素的索引
			return nextIndex;
		}

		public int previousIndex() {	//返回下一次调用previous返回的元素的索引
			return nextIndex - 1;
		}

		public void remove() {
			checkForComodification();
			Entry<E> lastNext = (Entry)data[lastReturned.next];
			try {
				ArrayLinkedList.this.remove(lastReturned);	//移除上一层调用next()或previous返回的元素
			} catch (NoSuchElementException e) {
				throw new IllegalStateException();
			}
			if (next == lastReturned)	//表明是调用previous后才调用remove方法
				next = lastNext;
			else
				nextIndex--;		//元素减少。nextIndex--
			lastReturned = header;	//重置lastReturned
			expectedModCount++;
		}

		public void set(E e) {
			if (lastReturned == header)
				throw new IllegalStateException();
			checkForComodification();
			lastReturned.element = e;
		}

		public void add(E e) {
			checkForComodification();
			lastReturned = header;
			addBefore(e, next);	//在上一次调用next返回的元素之后,在上次调用previous返回的元素之前添加e
			nextIndex++;	//元素增加,索引增加,保证下次调用next()不是返回添加的元素
			expectedModCount++;
		}

		final void checkForComodification() {
			if (modCount != expectedModCount)
				throw new ConcurrentModificationException();
		}
	}
}




下面给出的是测试的代码,所有方法我都测试过了。
public class TestMyList {
	public static void main(String[] args) {
		ArrayLinkedList<String> al  = new ArrayLinkedList<String>();
		al.add("My");
		al.add("Array");
		al.add("LinkedList");
		al.add("end");
		al.remove("My");
		al.add("new");
		al.remove(1);
		al.add("GG");
		al.add("haha");
		al.removeFirst();
		al.removeLast();
		al.addFirst("zhis");
		al.addLast("is");
		al.remove(2.3);
		ArrayList<String> ar = new ArrayList<String>();
		ar.add("123");ar.add("456");
		al.addAll(1, ar);
		Object[] data = al.data;
		for(int i=0;i<data.length;i++){
			System.out.println(data[i]);
		}
		System.out.println("size:"+al.size());
		ListIterator<String> it = al.listIterator(0);
		Iterator<String> it2 = al.iterator();
		while(it2.hasNext()){
			System.out.print(it2.next()+" ");
		}
		System.out.println();
		System.out.print(it.next()+" ");
		System.out.print(it.next()+" ");
		it.remove();
		System.out.print(it.next()+" " );
		System.out.print(it.previousIndex()+" ");
		System.out.print(it.previous()+" ");
		System.out.print(it.previous()+" ");
		System.out.print(it.nextIndex()+" ");
		System.out.println();
		System.out.println(al.lastIndexOf("GG"));
	}
}
分享到:
评论

相关推荐

    双向循环链表C++源代码

    双向的循环链表的C++源代码 实现正逆序遍历,链表归并,插入,删除,查询等基本操作

    C语言使用非循环双向链表实现队列

    在前面两篇博客中,我分别使用了静态数组和动态数组来模拟循环队列。但是线性表中和队列神似的莫过于链表了。我在前面也使用了大量的篇幅来讲述了链表的各种操作。我们使用一种比较特殊的链表——非循环双向链表来...

    数据结构和算法必知必会的50个代码实现

    ## 链表* 实现单链表、循环链表、双向链表,支持增删操作* 实现单链表反转* 实现两个有序的链表合并为一个有序链表* 实现求链表的中间结点 ## 栈* 用数组实现一个顺序栈* 用链表实现一个链式栈* 编程模拟实现一个...

    leetcode爬楼梯排列组合解法-algorithm_practice:对数据结构、算法相关的编程实践(DataStructureandAl

    实现单链表、循环链表、双向链表 支持增删操作 实现单链表反转 实现两个有序的链表合并为一个有序链表 实现求链表的中间结点 实现:assignment1 【任务2 - 栈、队列与递归】 1、栈 用数组实现一个顺序栈 用链表实现...

    validnumberleetcode自动机-LearingTripofNoah:我自己的学习之旅,天天学习至此方休

    实现单链表、循环链表、双向链表,支持增删操作 实现单链表反转 实现两个有序的链表合并为一个有序链表 实现求链表的中间结点 附加练习: Three Sum(求三数之和) 英文版: 中文版: Majority Element(求众数) ...

    精心整理史上最全的数据结构flash演示动画,共5个版本,祝大家考研成功!

    \数据结构flash演示\版本2\2.3 线性表的链式表示和实现-双向循环链表中右边插入节点.swf \数据结构flash演示\版本2\2.3 线性表的链式表示和实现-双向循环链表中左边插入节点.swf \数据结构flash演示\版本2\2.3 ...

    谭浩强C语言程序设计,C++程序设计,严蔚敏数据结构,高一凡数据结构算法分析与实现.rar

    10.4.2 使用字符串指针变量与字符数组的区别 158 10.5 函数指针变量 159 10.6 指针型函数 160 10.7 指针数组和指向指针的指针 161 10.7.1 指针数组的概念 161 10.7.2 指向指针的指针 164 10.7.3 main 函数的参数 166...

    谭浩强C语言程序设计,C++程序设计,严蔚敏数据结构,高一凡数据结构算法分析与实现.rar )

    10.4.2 使用字符串指针变量与字符数组的区别 158 10.5 函数指针变量 159 10.6 指针型函数 160 10.7 指针数组和指向指针的指针 161 10.7.1 指针数组的概念 161 10.7.2 指向指针的指针 164 10.7.3 main 函数的参数 166...

    C++语言描述(PDF合集)

    3.4.5 循环链表 93 3.4.6 与公式化描述方法的比较 94 3.4.7 双向链表 95 3.4.8 小结 96 3.5 间接寻址 99 3.5.1 基本概念 99 3.5.2 操作 100 3.6 模拟指针 102 3.6.1 SimSpace的操作 103 3.6.2 采用模拟指针的链表 ...

    数据结构算法与应用(C++语言描述).rar

    3.4.5 循环链表 93 3.4.6 与公式化描述方法的比较 94 3.4.7 双向链表 95 3.4.8 小结 96 3.5 间接寻址 99 3.5.1 基本概念 99 3.5.2 操作 100 3.6 模拟指针 102 3.6.1 SimSpace的操作 103 3.6.2 采用模拟指针的链表 ...

    数据结构C++描述

    3.4.5 循环链表 93 3.4.6 与公式化描述方法的比较 94 3.4.7 双向链表 95 3.4.8 小结 96 3.5 间接寻址 99 3.5.1 基本概念 99 3.5.2 操作 100 3.6 模拟指针 102 3.6.1 SimSpace的操作 103 3.6.2 采用模拟指针的链表 ...

    数据结构 C++描述

    3.4.5 循环链表 93 3.4.6 与公式化描述方法的比较 94 3.4.7 双向链表 95 3.4.8 小结 96 3.5 间接寻址 99 3.5.1 基本概念 99 3.5.2 操作 100 3.6 模拟指针 102 3.6.1 SimSpace的操作 103 3.6.2 采用模拟指针的链表 ...

    数据结构算法与应用-C__语言描述

    3.4.5 循环链表 93 3.4.6 与公式化描述方法的比较 94 3.4.7 双向链表 95 3.4.8 小结 96 3.5 间接寻址 99 3.5.1 基本概念 99 3.5.2 操作 100 3.6 模拟指针 102 3.6.1 SimSpace的操作 103 3.6.2 采用模拟指针的链表 ...

    数据结构算法与应用-C++语言描述

    3.4.5 循环链表 93 3.4.6 与公式化描述方法的比较 94 3.4.7 双向链表 95 3.4.8 小结 96 3.5 间接寻址 99 3.5.1 基本概念 99 3.5.2 操作 100 3.6 模拟指针 102 3.6.1 SimSpace的操作 103 3.6.2 采用模拟指针的链表 ...

    数据结构、算法与应用--C++语言描述

    3.4.5 循环链表 93 3.4.6 与公式化描述方法的比较 94 3.4.7 双向链表 95 3.4.8 小结 96 3.5 间接寻址 99 3.5.1 基本概念 99 3.5.2 操作 100 3.6 模拟指针 102 3.6.1 SimSpace的操作 103 3.6.2 采用模拟指针的链表 ...

    数据结构(C语言描述)

    3.4.5 循环链表 93 3.4.6 与公式化描述方法的比较 94 3.4.7 双向链表 95 3.4.8 小结 96 3.5 间接寻址 99 3.5.1 基本概念 99 3.5.2 操作 100 3.6 模拟指针 102 3.6.1 SimSpace的操作 103 3.6.2 采用模拟指针的链表 ...

    数据结构算法与应用-C C++语言描述

    3.4.5 循环链表 93 3.4.6 与公式化描述方法的比较 94 3.4.7 双向链表 95 3.4.8 小结 96 3.5 间接寻址 99 3.5.1 基本概念 99 3.5.2 操作 100 3.6 模拟指针 102 3.6.1 SimSpace的操作 103 3.6.2 采用模拟指针的链表 ...

    数据结构算法与应用-C++语言描述.rar

    3.4.5 循环链表 93 3.4.6 与公式化描述方法的比较 94 3.4.7 双向链表 95 3.4.8 小结 96 3.5 间接寻址 99 3.5.1 基本概念 99 3.5.2 操作 100 3.6 模拟指针 102 3.6.1 SimSpace的操作 103 3.6.2 采用模拟指针...

Global site tag (gtag.js) - Google Analytics