实现TreeSet类,其中迭代器使用二叉查找树

5 篇文章 0 订阅
2 篇文章 0 订阅

TreeSet的实现类

这里主要是实现TreeSet的迭代器的hasNext()、next()、remove()这三个方法。
本例中所用到的节点都为其添加了一条指向其父节点的parent引用


import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;

public class MyTreeSet<E extends Comparable<? super E>> implements Iterable<E>{

	private static class Node<E>{
		E data;
		Node<E> left;
		Node<E> right;
		Node<E> parent;
		public Node(E data, Node<E> parent) {
			this(data, null, null, parent);
		}
		public Node(E data, Node<E> left, Node<E> right, Node<E> parent) {
			this.data = data;
			this.left = left;
			this.right = right;
			this.parent = parent;
		}
	}
	
	private Node<E> root;
	private int theSize;
	private int modCount;//记录自从构造以来对集合所做改变的次数
	
	public MyTreeSet() {
		root = null;
		theSize = 0;
		modCount = 0;
	}
	
	public void insert(E x) {
		root = insert(x, root, null);
	}
	
	public int size() {
		return theSize;
	}
	private Node<E> insert(E x, Node<E> t, Node<E> parent) {
		if(t == null) {
			this.theSize++;
			modCount++;
			return new Node<E>(x, parent);
		}
		int compareResult = x.compareTo(t.data);
		if(compareResult < 0) {
			t.left = insert(x, t.left, t);
		}else if(compareResult > 0) {
			t.right = insert(x, t.right, t);
		}
		return t;
	}
	public void remove(E x) {
		root = remove(x, root);
	}
	/**
	 * 如果节点是一片叶子,那么可以立即删除。
	 * 如果节点有一个儿子,则该节点可以通过其父节点调整自己的链以绕过该节点去链接该节点的儿子节点后被删除。
	 * 如果右两个儿子节点,则用其右子树的最小的数据代替该节点的数据并递归地删除那个节点。
	 * @param x
	 * @param t
	 * @return
	 */
	private Node<E> remove(E x, Node<E> t) {
		if(t == null) 
			return t;
		int compareResult = x.compareTo(t.data);
		if(compareResult < 0) {
			t.left = remove(x, t.left);
		}else if(compareResult > 0) {
			t.right = remove(x, t.right);
		}else {
			if(t.left != null && t.right != null){// Two children
				t.data = findMin(t.right).data;
				t.right = remove(t.data, t.right);
			}else { //One children or No children
				if(t.left != null) {
					t.left.parent = t.parent;
				}else if(t.right != null) {
					t.right.parent = t.parent;
				}
				t = (t.left != null) ? t.left : t.right;
			}
			this.theSize--;
			modCount++;
		}
		return t;
	}

	/**
	 * 返回树T中最小节点
	 * @param T
	 * @return
	 */
	private Node<E> findMin(Node<E> T) {
		while(T.left != null) {
			T = T.left;
		}
		return T;
	}

	@Override
	public java.util.Iterator<E> iterator() {
		return new TreeSetIterator();
	}
	
	private class TreeSetIterator implements Iterator<E>{
		private Node<E> current;//下一个最小节点
		private Node<E> previous;//最近一次被遍历的节点
		//记录集合结构被修改次数 与modCount配合,防止在迭代时通过调用MyTreeSet的插入或删除操作使MyTreeSet的结构发生变化
		private int expecteddModCount;
		private boolean okToRemove;
		private boolean atEnd;
		

		@Override
		public boolean hasNext() {
			return !atEnd;
		}

		@Override
		public E next() {
			if(modCount != expecteddModCount) {
				throw new ConcurrentModificationException();
			}
			if(!hasNext()) {
				throw new NoSuchElementException();
			}
			previous = current;
			//把current指向下一个要遍历的最小元素
			current = nextMin(current);
			//如果current=null,则遍历完所有节点
			if(current == null) {
				atEnd = true;
			}
			okToRemove = true;
			return previous.data;
		}
		/**
		 * 
		 */
		@Override
		public void remove() {
			if(modCount != expecteddModCount) {
				throw new ConcurrentModificationException();
			}
			if(!okToRemove) {
				throw new IllegalStateException();
			}
			/*
			 * 如果删除previous所引用的节点有左、右子树时,则current重新回到previous节点
			* 因为MyTreeSet.this.remove()在实现时,对单子树和双子树节点进行了分类删除操作。
			* 对于拥有双子树的节点只进行了内容上的替换,实际删除的是被替换的叶子节点。
			* 另外也只有在删除拥有左、右子树的节点时才会影响到current引用,
			* 因为此时current所引用的节点属于previous节点的右子树中的叶子节点。
			* 其它情况下删除previous引用的节点不影响current所引用的节点
			 */
			if(previous.right != null && previous.left != null) {
				current = previous;
			}
			//删除非根节点
			if(previous.parent != null) {
				//从previous的祖先节点开始删除,否则previous的父节点可能回丢失子树
				MyTreeSet.this.remove(previous.data, previous.parent);				
			}else {//删除根节点
				root = MyTreeSet.this.remove(previous.data, previous);
			}
			expecteddModCount = modCount;
			okToRemove = false;
		}
		/**
		 * 返回下一个大于T值的最小节点
		 * @param T
		 * @return
		 */
		private Node<E> nextMin(Node<E> T) {
			//若存在右子树,则下一个大于T值的最小节点一定在右子树中
			if(T.right != null) {
				return findMin(T.right);
			}else {//若没有右子树,则下一个大于T值的最小节点一定在祖先节点中
				return parentMin(T);
			}
		}
		/**
		 * 将current指向root树中的最小元素
		 */
		public TreeSetIterator() {
			current = findMin(root);
			previous = null;
			expecteddModCount = modCount;
			okToRemove = false;
			atEnd = false;
		}
		/**
		 * 返回T树的祖先节点中未被遍历的最小节点
		 * @param T
		 * @return
		 */
		private Node<E> parentMin(Node<E> T) {
			Node<E> child = T;
			T = T.parent;
			while(T != null && child != T.left) {
				child = T;
				T = T.parent;
			}
			return T;
		}
		
		
	}
	

	public static void main(String[] args) {
		MyTreeSet<Integer> set = new MyTreeSet<>();
		int[] a = new int[]{3, 1, 4, 6, 9, 2, 5, 7, 10, 8};
		for (int i : a) {
			set.insert(i);
		}
		
		Iterator<Integer> itr = set.iterator();
		while(itr.hasNext()) {
			int k = itr.next();
			if(k % 2 == 0) {
//				set.remove(k);
				itr.remove();
			}else
				System.out.print(k + " ");				
		}
	}




}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值