算法基础——数据结构

1 篇文章 0 订阅
1 篇文章 0 订阅

队列

1.数组实现


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

public class HeapSort<Item> implements Iterable<Item> {
    private Item[] arr;       // queue elements
    private int N;          // number of elements on queue
    private int first;      // 队列第一个元素的索引
    private int last;       // 下一个可用插槽的索引


    /**
     * Initializes an empty queue.
     */
    public HeapSort() {
        arr = (Item[]) new Object[1];
        N = 0;
        first = 0;
        last = 0;
    }

    public boolean isEmpty() {
        return N == 0;
    }

    public int size() {
        return N;
    }

    private void resize(int capacity) {
        Item[] temp = (Item[]) new Object[capacity];
        for (int i = 0; i < N; i++) { //若此时N=1,那么仅for循环一次
            temp[i] = arr[(first + i) % arr.length];//这边用first是因为,firt永远指向
  		// 下一个要先被删除的元素,即意味着first指向的元素以及该元素后面的元素都十分重要,很可能还没被取出。
		// 而firt+i,能够保证原始数组中的下一个要被删除(取出)的元素放在新数组的第一个,根据i的变化,
		// first所指向的位置后面的元素依次往后存放于新数组中
        }
        arr = temp;
        first = 0;//由于旧数组的first很可能不是指向的0,因此要置为0 ,因为创建了新数组,下一个要被取出的元素在新数组的索引为0处
        last  = N;//last=N,很关键,last永远指向下一个元素被存放的地方,因此,他要找一个空位,即索引为N处,即有几个元素,就存放在
		// 索引为几处,如旧数组将两个元素转移到了新数组中(arr[0],arr[1]),那么first指向0,last指向2处——arr[2]的位置
    }

    public void enqueue(Item item) {
        if (N == arr.length) resize(2*arr.length);  
        arr[last++] = item;                        
        if (last == arr.length) last = 0;          //一旦发现元素已填充满数组,立马将last置为0
        N++;//注意,不是栈了,栈中是arr[N++],因此,这里别忘了N++,上面也只能使用last==arr.length
    }

    public Item dequeue() {
        if (isEmpty()) throw new NoSuchElementException("Queue underflow");
        Item item = arr[first];
        arr[first] = null;                            // to avoid loitering
        N--;  //注意N--得在 if(N > 0 && N == arr.length/4)语句的前面
        first++;
        if (first == arr.length) first = 0;   //表明,数组元素已经被删完了一轮了,此时,first重置为0,因为
		//  在索引0处又存放了新进来的一些元素(出现的情况(画图)),比如数组长度为4,先添加4个元素,然后删掉两个,
		// 此时,last=0,first=2,再添加两个,此时last=2,first=3,再删除两个,此时first=0,last=2)
        // shrink size of array if necessary
        if (N > 0 && N == arr.length/4) resize(arr.length/2); //这两个if的语句顺序也不能对调,注意一下,因为会影响到arr.length
        return item;
    }

    public Item peek() {
        if (isEmpty()) throw new NoSuchElementException("Queue underflow");
        return arr[first];
    }


    /**
     * Returns an iterator that iterates over the items in this queue in FIFO order.
     * @return an iterator that iterates over the items in this queue in FIFO order
     */
    public Iterator<Item> iterator() {
        return new ArrayIterator();
    }

    // an iterator, doesn't implement remove() since it's optional
    private class ArrayIterator implements Iterator<Item> {
        private int i = 0;
        public boolean hasNext()  { return i < N;                               }
        //return i < N 等价于 N > 0
        public void remove()      { throw new UnsupportedOperationException();  }

        public Item next() {
            if (!hasNext()) throw new NoSuchElementException();
            Item item = arr[(i + first) % arr.length];//和上面的for循环一样,为啥要%arr.length呢?
		//因为假设数组长度为4,first指向3,所以,item[0]=arr[3];
		//然后i++,此时item[1]=arr[4%4]=arr[0];若没有%arr.length,arr[4]就数组角标越界了
		//因此,%arr.length是为了能够循环遍历arr数组
            i++;
            return item;
        }
    }
}

原理图解:
在这里插入图片描述

2.链表实现

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

public class Queue<Item> implements Iterable<Item> {
    private Node<Item> first;    // beginning of queue
    private Node<Item> last;     // end of queue
    private int N;               // number of elements on queue

    private static class Node<Item> {
        private Item item;
        private Node<Item> next;
    }

    public Queue() {
        first = null;
        last  = null;
        N = 0;
    }

    public boolean isEmpty() {
        return first == null;
    }

    public int size() {
        return N;
    }

    public Item peek() {
        if (isEmpty()) throw new NoSuchElementException("Queue underflow");
        return first.item;
    }
    //表头删除元素
    public void enqueue(Item item) {
        Node<Item> oldlast = last;
        last = new Node<Item>();
        last.item = item;
        last.next = null;
        if (isEmpty()) first = last; //如果刚开始添加元素,显然,last为null
        // 因此oldlast也为null。但last=new Node<Item>(),所以if语句上面的代码都OK,不会空引用异常
        // 但oldlast.next会报空引用以长,因为oldlast=null。与此同时first也为null,因此first=last,
        // 让这两个指针同时指向新加入的元素
        else           oldlast.next = last;
        N++;
    }
    //表尾添加元素
    public Item dequeue() {
        if (isEmpty()) throw new NoSuchElementException("Queue underflow");
        Item item = first.item;
        first = first.next; //如果正好把最后一个元素删了,那么first.next=null,所以fisrt=null.
        N--;
        if (isEmpty()) last = null;   // to avoid loitering,尽管first=null,但last还指向最后一个被删掉的元素
        // 因此要手动置为null,这里可以画一下图,一眼明了。
        return item;
    }

    /**
     * Returns a string representation of this queue.
     *
     * @return the sequence of items in FIFO order, separated by spaces
     */
    public String toString() {
        StringBuilder s = new StringBuilder();
        for (Item item : this) {
            s.append(item);
            s.append(' ');
        }
        return s.toString();
    } 

    /**
     * Returns an iterator that iterates over the items in this queue in FIFO order.
     *
     * @return an iterator that iterates over the items in this queue in FIFO order
     */
    public Iterator<Item> iterator()  {
        return new ListIterator(first);  
    }

    // an iterator, doesn't implement remove() since it's optional
    private class ListIterator implements Iterator<Item> { //从头开始遍历,和栈一模一样
        private Node<Item> current;

        public ListIterator(Node<Item> first) {
            current = first;
        }

        public boolean hasNext()  { return current != null;                     }
        public void remove()      { throw new UnsupportedOperationException();  }

        public Item next() {
            if (!hasNext()) throw new NoSuchElementException();
            Item item = current.item;
            current = current.next;    //这样我current.next不会影响到first指针的移动
            return item;
        }
    }
}



1.数组实现

字符串定容栈

import java.util.Iterator;

public class FixedCapacityStackOfStrings implements Iterable<String> {
    private String[] a;  // holds the items
    private int N;       // number of items in stack

    public FixedCapacityStackOfStrings(int capacity) {
        a = new String[capacity];
        N = 0;
    }

    public boolean isEmpty()            {  return N == 0;                    }
    public boolean isFull()             {  return N == a.length;             }
    
    //比如添加第一个元素,该元素位置显然在a[0]处,此时N也应该等于1.
    public void push(String item)       {  a[N++] = item;                    }
    //先--N,再返回是因为a[N--]这个元素是不存在的,比如我要删除a[4],此时N肯定为5,那么a[--N]完美契合。
    public String pop()                 {  return a[--N];                    }
    public String peek()                {  return a[N-1];                    }
    //对于自定义可迭代的数据类型,类要实现接口Iterable,还要实现该接口的方法Iterator<Item> iterator();
    public Iterator<String> iterator()  { return new ReverseArrayIterator(); }

    private class ReverseArrayIterator implements Iterator<String> {
        private int i = N;//这边新建变量i是为了避免在遍历时,a[--N]改变N的值,这是不允许发生的。

        public boolean hasNext() { return i > 0;  }
        public String next()     { return a[--i]; }
        
        public void remove() {
            throw new UnsupportedOperationException();
        }
	}
}

注:在构造方法里面对数组长度进行定义是十分普遍的做法,这样在创建一个栈时就可以指定它的大小。
下面是一张很经典的栈应用实例图:
在这里插入图片描述
从图中不难看出,对象会游离,即pop的对象其实还存在在数组中,但因为N的限制,导致访问不到游离的对象,必须对游离的对象置为null。

泛型定容字符串

import java.util.Iterator;

public class FixedCapacityStack<Item> implements Iterable<Item> {
    private Item[] a;    // holds the items
    private int N;       // number of items in stack

    public FixedCapacityStack(int capacity) {
        a = (Item[]) new Object[capacity];//注意,泛型数组的创建方式
        N = 0;
    }

    public boolean isEmpty()          {  return N == 0;                    }
    public void push(Item item)       {  a[N++] = item;                    }
    public Item pop()                 {  return a[--N];                    }
    public Iterator<Item> iterator()  { return new ReverseArrayIterator(); }


    private class ReverseArrayIterator implements Iterator<Item> {
        private int i = N;

        public boolean hasNext() { return i > 0;  }
        public Item next()       { return a[--i]; }
        
        public void remove() {
            throw new UnsupportedOperationException();
        }
    }
}

下压(LIFO)栈(长度可调)

最终版本:

import java.util.Iterator;

public class ResizingArrayStack<Item> implements Iterable<Item> {
	private int N=0;
	private Item[] a=(Item[])new Object[1];//这边两个赋值可以放到构造函数中,除此之外,要注意这边不是(Item)new Object[1];
	
	public boolean isEmpty() {
		return N==0;
	}
	public int size() {
		return N;
	}
	public void push(Item item) {
		if(N==a.length)     //在添加新元素前判断数组长度是否不够。
			resize(a.length*2);
		a[N++]=item;
	}
	public Item pop() {
		if (isEmpty()) throw new NoSuchElementException("Stack underflow");
		Item item= a[--N]; 	//比如N=5,我删掉了a[4],那么a[4]就游离了,此时N=4,这边a[--N]等价于a[N-1]
		a[N]=null;   		//防止对象游离,如果上面是a[N-1],那么这边a[N-1]=null,且在后面得加上N--;
		//特别注意,如果Item类型是int的话,这边不能置为null,int型的元素无法被置为null,他们默认为0。
		if(N>0 && N==a.length/4)	//删完了之后发现N浪费太多了,此时再缩小数组长度
			resize(a.length/2);//一个4,一个2,顺序不要搞反了
		return item;  		//返回的item就是被置为null的值。
	}
	public void resize(int len) {
		Item[] temp=(Item[])new Object[len];
		for(int i=0;i<N;i++) {//这边i<N,而不是len!!!
	//	如果i<len,数组无论变大还是变小,都会多遍历一半,浪费时间
			temp[i]=a[i];
		}
		a=temp; //把加长版新数组再次赋给a!!!
	}
	public Item peek() {
        if (isEmpty()) throw new NoSuchElementException("Stack underflow");
        return a[N-1];
    }
	
	public Iterator<Item>  iterator(){
		return new ReverseArrayIterator();//Itertor是一个接口,因此,我返回的对象一定要继承该接口
	}
	private class ReverseArrayIterator implements Iterator<Item>{
		private int i=N;//也可以放到构造函数中进行赋值
		/*public ReverseArrayIterator(){
			i=N;*/
		public boolean hasNext() {
			return i>0;
		}
		public Item next() {
			if (!hasNext()) throw new NoSuchElementException();
			return a[--i];
		}
		public void remove() {
			throw new UnsupportedOperationException();
		}
	}
}

注:

  1. 为什么N=a.length/4,因为如果a.length/2==N时resize数组长度,那么我push一下,又要resize,pop一下,又要resize,这样会频繁的调整数组大小(中间会频繁的创建数组,浪费时间)
    自从数组长度可调以及避免了对象游离之后,示意图如下:

在这里插入图片描述
为什么要逆序迭代遍历数组(ReverseArrayIterator
因为上述代码是堆栈,先进后出,后进先出,符合栈的元素存取顺序。

2.链表实现

下压栈

原理图,遵循FILO(LIFO)原则。这张图的思想就是链表实现栈的思想,十分重要!
栈的元素添加和删除操作都在链表的表头执行,先进先出。
在这里插入图片描述
代码:

/*
 * 链表实现
 */
import java.util.Iterator;
import java.util.NoSuchElementException;

public class Stack<Item> implements Iterable<Item> {
    private Node<Item> first;     // top of stack
    private int N;                // size of the stack

    // helper linked list class
    private static class Node<Item> {
        private Item item;
        private Node<Item> next;
    }

    public Stack() {
        first = null;
        N = 0;
    }

    public boolean isEmpty() {
        return first == null;
    }

    public int size() {
        return N;
    }
	//表头添加
    public void push(Item item) {
        Node<Item> oldfirst = first;
        first = new Node<Item>();
        first.item = item;
        first.next = oldfirst;
        N++;
    }

    /**
     * Removes and returns the item most recently added to this stack.
     */
     //表头删除
    public Item pop() {
        if (isEmpty()) throw new NoSuchElementException("Stack underflow");
        Item item = first.item;        // save item to return
        first = first.next;            // delete first node
        N--;
        return item;                   // return the saved item
    }

    /**
     * Returns (but does not remove) the item most recently added to this stack.
     */
    public Item peek() {
        if (isEmpty()) throw new NoSuchElementException("Stack underflow");
        return first.item;
    }

    /**
     * Returns a string representation of this stack.
     *
     * @return the sequence of items in this stack in LIFO order, separated by spaces
     */
    public String toString() {
        StringBuilder s = new StringBuilder();
        for (Item item : this) {
            s.append(item);
            s.append(' ');
        }
        return s.toString();
    }

    /**
     * Returns an iterator to this stack that iterates through the items in LIFO order.
     *
     * @return an iterator to this stack that iterates through the items in LIFO order
     */
    public Iterator<Item> iterator() {
        return new ListIterator(first);
    }

    // an iterator, doesn't implement remove() since it's optional
    private class ListIterator implements Iterator<Item> {
        private Node<Item> current;

        public ListIterator(Node<Item> first) {
            current = first;
        }

        public boolean hasNext() {
            return current != null;
        }
        
        public void remove() {
            throw new UnsupportedOperationException();
        }

        public Item next() {
            if (!hasNext()) throw new NoSuchElementException();
            Item item = current.item;
            current = current.next; 
            return item;
        }
    }
}

背包

1.数组实现

import java.util.Iterator;

public class BagArray<Item> implements Iterable<Item> {
	private int N;
	private Item[] a;

	public BagArray() {
		N = 0;
		a = (Item[]) new Object[1];
	}

	public boolean isEmpty() {
		return N == 0;
	}

	public int size() {
		return N;
	}

	public void push(Item item) {
		if (N == a.length) // 在添加新元素前判断数组长度是否不够。
			resize(a.length * 2);
		a[N++] = item;
	}

	public void resize(int len) {
		Item[] temp = (Item[]) new Object[len];
		for (int i = 0; i < len; i++) {
			temp[i] = a[i];
		}
		a = temp; // 把加长版新数组再次赋给a!!!
	}

	public Iterator<Item> iterator() {
		return new ArrayIterator(); //不用再逆序遍历了。
	}

	private class ArrayIterator implements Iterator<Item> {
		private int i = 0;

		public boolean hasNext() {
			return N > i;//等价于N > 0;
		}

		public Item next() {
			return a[i++];
		}

		public void remove() {
		}
	}
}

2.链表实现

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

public class Bag<Item> implements Iterable<Item> {
	private Node<Item> first; // beginning of bag
	private int N; // number of elements in bag

	private static class Node<Item> {
		private Item item;
		private Node<Item> next;
	}

	public Bag() {
		first = null;
		N = 0;
	}

	public boolean isEmpty() {
		return first == null;
	}

	public int size() {
		return N;
	}

	public void add(Item item) {
		Node<Item> oldfirst = first;
		first = new Node<Item>();
		first.item = item;
		first.next = oldfirst;
		N++;
	}

	public Iterator<Item> iterator() {
		return new ListIterator(first);
	}

	// an iterator, doesn't implement remove() since it's optional
	private class ListIterator implements Iterator<Item> {
		private Node<Item> current;

		public ListIterator(Node<Item> first) {
			current = first;
		}

		public boolean hasNext() {
			return current != null;
		}

		public void remove() {
			throw new UnsupportedOperationException();
		}

		public Item next() {
			if (!hasNext())
				throw new NoSuchElementException();
			Item item = current.item;
			current = current.next;
			return item;
		}
	}
}

链表

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值