java数据结构--线性结构
一、数据结构
数据结构由数据和结构两部分组成,就是将数据按照一定的结构组合起来,这样不同的组合方式有不同的效率,可根据需求选择不同的结构应用在相应在场景。数据结构大致
分为两类:线性结构(如数组,链表,队列,栈等),非线性结构(如树,图,表等)。本文介绍下线性结构,下章介绍非线性结构。
二、数组
数组表示一组有限个相同类型的数据的集合,顺序存储,下标从0开始,其特点是可以根据下标快速的查找到元素,但在增加和删除元素时会导致大量的数据位置的变动,即这
种情况下性能不高,故数组一般多用于查找频繁,增,删较少的情况。
下图为一个二维数组的结构图:
插入元素:
当往数组某位置上插入元素时,需要将位置后的所有元素往后移动一个位置。
删除元素:
当删除数组上的某个元素时,需要将该元素后的所有元素的位置往前移动一个位置。
下面简单实现数组中插入元素和删除元素功能:
public class ArrayDemo<T> { private Object[] array ; private int length = 0; private final static int DEFAULT_CAPACITY = 10; public ArrayDemo(){ super(); this.array = new Object[DEFAULT_CAPACITY]; this.length = DEFAULT_CAPACITY; } public ArrayDemo(int length){ super(); if(length < 0){ throw new IllegalArgumentException("error length:"+length); } this.array = new Object[length]; this.length = length; } public ArrayDemo(Collection<? extends T> c){ array = c.toArray(); length = c.size(); if(array.getClass() != Object[].class){ array = Arrays.copyOf(array, length, Object[].class); } } /** * 在数组array的index位置处插入一个元素t,如果已经满了,则移除最后一个元素 * @param array * @param t * @param indext */ public void insert(T t, int index){ if(null == t){ throw new NullPointerException("null Pointer!"); } if(index < 0 || index > length-1){ throw new IndexOutOfBoundsException("index is error"); } for(int pos = length-1; pos>index; pos--){ array[pos] = array[pos-1]; } array[index] = t; } /** * 删除指定位置上的数组元素 * @param array * @param index */ public void delete(int index){ if(null == array){ throw new NullPointerException("null Pointer!"); } int length = array.length; if(index < 0 || index > length-1){ throw new IndexOutOfBoundsException("index is error"); } for(int pos = index; pos < length-1; pos++){ array[pos] = array[pos+1]; } array[length-1] = null; } /** * 遍历输出数组中所有元素 */ public void trans(){ if(null == array){ throw new NullPointerException("null Pointer!"); } for(int pos=0; pos< length; pos++){ System.out.println(array[pos]); } } }
public class Person { private String name; private String sex; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } @Override public String toString() { return "Person [name=" + name + ", sex=" + sex + "]"; } public Person(String name, String sex) { super(); this.name = name; this.sex = sex; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((sex == null) ? 0 : sex.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (sex == null) { if (other.sex != null) return false; } else if (!sex.equals(other.sex)) return false; return true; } }
测试类:
public class TestArray { public static void main(String[] args) { ArrayDemo<Person> array = new ArrayDemo<>(); Person p = new Person("张三", "m"); array.insert(p, 0); array.trans(); array.delete(0); System.out.println("---"); array.trans(); } }
三、链表
链表是一种有序的列表。链表的内容通常存储在内存中分散的位置上。链表由节点组成,每个节点的结构都是相同的。节点分为数据域和链域,数据域顾名思义,就是存放节点
节点的内容,链域存放的是下一个节点的指针或引用。如果是双向链表的话,链域中还会有前一个节点的指针或引用。下图为单向链表各节点间的关系图。
下面来实现一个简单的链表结构
节点类:
public class Node<T> { private T data; private Node<T> pre; private Node<T> next; public Node(){ super(); this.pre = null; this.next = null; } public Node(T data){ super(); this.data = data; this.pre = null; this.next = null; } public Node(T data, Node<T> pre, Node<T> next){ super(); this.data = data; this.pre = pre; this.next = next; } public T getData() { return data; } public void setData(T data) { this.data = data; } public Node<T> getPre() { return pre; } public void setPre(Node<T> pre) { this.pre = pre; } public Node<T> getNext() { return next; } public void setNext(Node<T> next) { this.next = next; } }
链表类
public class LinkedListDemo<T> { private Node<T> head;//头结点 private Node<T> tail;//尾节点 private int size;//链表大小 public LinkedListDemo(){ head = new Node<T>(null, null, null); tail = new Node<T>(null, head, null); head.setNext(tail); size = 0; } public MyIterator<T> iterator(){ return new MyIterator<T>(); } public void add(T data){ Node<T> node = new Node<T>(data); node.setPre(tail.getPre()); tail.getPre().setNext(node); tail.setPre(node); node.setNext(tail); size++; } public void remove(T data){ Node<T> node = head; while(tail != node.getNext()){ Node<T> currentNode = node.getNext(); if(currentNode.getData().equals(data)){ currentNode.getPre().setNext(currentNode.getNext()); currentNode.getNext().setPre(currentNode.getPre()); size--; break; } node = currentNode; } } public void print(){ Node<T> node = head; while(tail != node.getNext()){ Node<T> currentNode = node.getNext(); System.out.println(currentNode.getData().toString()); node = currentNode; } } /** * * 项目名: adt * 类名: LinkedListDemo.java * 类描述: 定义一个该链表的迭代器来访问 * 备注: * 创建日期:2014-10-10 * 创建时间:上午12:10:46 * @param <T> */ @SuppressWarnings("hiding") private class MyIterator<T> implements Iterator<T>{ @SuppressWarnings("unchecked") private Node<T> currentNode = (Node<T>) head.getNext();//节点读取当前位置 private Node<T> returnedNode = currentNode;//返回节点的位置 @Override public boolean hasNext() { return currentNode == tail? false:true; } @Override public T next() { if(!hasNext()){ throw new IndexOutOfBoundsException(); } returnedNode = currentNode; currentNode = currentNode.getNext(); return returnedNode.getData(); } @Override public void remove() { if(!hasNext()){ throw new NoSuchElementException(); } returnedNode.getPre().setNext(returnedNode.getNext()); returnedNode.getNext().setPre(returnedNode.getPre()); returnedNode = returnedNode.getNext(); currentNode = returnedNode; size--; } } }
测试类:
public class TestDemo { public static void main(String[] args) { LinkedListDemo<Person> list = new LinkedListDemo<Person>(); //往链表中加入10个元素 for(int i=0; i<10;i++){ Person p = new Person("zhang"+i, "m"); list.add(p); } list.print(); System.out.println("========"); Person p = new Person("zhang1", "m"); list.remove(p);//移除自定的元素 list.print(); System.out.println("========"); Person p1 = new Person("zhang4", "m"); Iterator<Person> iterator = list.iterator(); while(iterator.hasNext()){ Person person = iterator.next(); if(person.equals(p1)){ iterator.remove();//迭代器移除制定元素 break; } } list.print(); } }结果:
Person [name=zhang0, sex=m] Person [name=zhang1, sex=m] Person [name=zhang2, sex=m] Person [name=zhang3, sex=m] Person [name=zhang4, sex=m] Person [name=zhang5, sex=m] Person [name=zhang6, sex=m] Person [name=zhang7, sex=m] Person [name=zhang8, sex=m] Person [name=zhang9, sex=m] ======== Person [name=zhang0, sex=m] Person [name=zhang2, sex=m] Person [name=zhang3, sex=m] Person [name=zhang4, sex=m] Person [name=zhang5, sex=m] Person [name=zhang6, sex=m] Person [name=zhang7, sex=m] Person [name=zhang8, sex=m] Person [name=zhang9, sex=m] ======== Person [name=zhang0, sex=m] Person [name=zhang2, sex=m] Person [name=zhang3, sex=m] Person [name=zhang5, sex=m] Person [name=zhang6, sex=m] Person [name=zhang7, sex=m] Person [name=zhang8, sex=m] Person [name=zhang9, sex=m]
四、队列
队列数据结构类似于生活中队列,有一个很重要的特性:先进先出。即增加元素肯定是在队列的尾部添加,删除元素肯定是删除队列头部的元素。队列的实现可以用数据结构,
也可以用链表结构。
下面简单是一个用数组结构实现的队列结构:
public class QueueDemo<T> { private Object[] object; /** * 队列容量 */ private int capicity; /** * 队列中元素的个数 */ private int size; private final static int DEFAULT_CAPICAL = 10; public QueueDemo(){ capicity = DEFAULT_CAPICAL; object = new Object[capicity]; } public QueueDemo(int capicity){ this.capicity = capicity; object = new Object[this.capicity]; } public int size(){ return size; } public boolean isEmpty(){ return size==0; } /** * 往队列中添加元素 * @param t */ public void add(T t){ if(size == capicity){ throw new IndexOutOfBoundsException("queue is full"); } object[size++]=t; } /** * 移除队列中的元素 */ public void remove(){ if(isEmpty()){ throw new IndexOutOfBoundsException("queue is empty"); } for(int pos = 0; pos < size-1; pos++){//将整个数组往前以一个位置 object[pos] = object[pos+1]; } size--; } public void clear(){ Arrays.fill(object, null); size=0; } public void print(){ for(int i=0; i<size; i++){ System.out.println(object[i].toString()); } } }
测试类:
public class TestQueue { /** * @param args */ public static void main(String[] args) { QueueDemo<Person> queue = new QueueDemo<Person>(); for(int i=0; i<10; i++){ Person p = new Person("zhang"+i, "m"); queue.add(p); } queue.print(); System.out.println("====="); while(queue.size() > 0){//依次删除队列头元素 queue.remove(); queue.print(); System.out.println("====="); } } }
输出:
Person [name=zhang0, sex=m] Person [name=zhang1, sex=m] Person [name=zhang2, sex=m] Person [name=zhang3, sex=m] Person [name=zhang4, sex=m] Person [name=zhang5, sex=m] Person [name=zhang6, sex=m] Person [name=zhang7, sex=m] Person [name=zhang8, sex=m] Person [name=zhang9, sex=m] ===== Person [name=zhang1, sex=m] Person [name=zhang2, sex=m] Person [name=zhang3, sex=m] Person [name=zhang4, sex=m] Person [name=zhang5, sex=m] Person [name=zhang6, sex=m] Person [name=zhang7, sex=m] Person [name=zhang8, sex=m] Person [name=zhang9, sex=m] ===== Person [name=zhang2, sex=m] Person [name=zhang3, sex=m] Person [name=zhang4, sex=m] Person [name=zhang5, sex=m] Person [name=zhang6, sex=m] Person [name=zhang7, sex=m] Person [name=zhang8, sex=m] Person [name=zhang9, sex=m] ===== Person [name=zhang3, sex=m] Person [name=zhang4, sex=m] Person [name=zhang5, sex=m] Person [name=zhang6, sex=m] Person [name=zhang7, sex=m] Person [name=zhang8, sex=m] Person [name=zhang9, sex=m] ===== Person [name=zhang4, sex=m] Person [name=zhang5, sex=m] Person [name=zhang6, sex=m] Person [name=zhang7, sex=m] Person [name=zhang8, sex=m] Person [name=zhang9, sex=m] ===== Person [name=zhang5, sex=m] Person [name=zhang6, sex=m] Person [name=zhang7, sex=m] Person [name=zhang8, sex=m] Person [name=zhang9, sex=m] ===== Person [name=zhang6, sex=m] Person [name=zhang7, sex=m] Person [name=zhang8, sex=m] Person [name=zhang9, sex=m] ===== Person [name=zhang7, sex=m] Person [name=zhang8, sex=m] Person [name=zhang9, sex=m] ===== Person [name=zhang8, sex=m] Person [name=zhang9, sex=m] ===== Person [name=zhang9, sex=m] ===== =====
五、栈
栈结构与队列类似,不过区别在于栈是先进后出的。即最先进栈的元素是最后一个出栈的。栈的结构也可以用数组或链表来实现。
下面简单实现一个基于数组结构的栈,实现只是稍微修改下上面队列结构的代码。
public class StackDemo<T> { private Object[] object; private int capicity; private int size; private final static int DEFAULT_CAPICAL = 10; public StackDemo(){ capicity = DEFAULT_CAPICAL; object = new Object[capicity]; } public StackDemo(int capicity){ this.capicity = capicity; object = new Object[this.capicity]; } public int size(){ return size; } public boolean isEmpty(){ return size==0; } public void add(T t){ if(size == capicity){ throw new IndexOutOfBoundsException("queue is full"); } object[size++]=t; } /** * 修改移除元素的代码 */ public void remove(){ if(isEmpty()){ throw new IndexOutOfBoundsException("queue is empty"); } object[--size]=null; } public void clear(){ Arrays.fill(object, null); size=0; } public void print(){ for(int i=0; i<size; i++){ System.out.println(object[i].toString()); } } }
测试类:
public class TestStack { /** * @param args */ public static void main(String[] args) { StackDemo<Person> queue = new StackDemo<Person>(); for(int i=0; i<10; i++){ Person p = new Person("zhang"+i, "m"); queue.add(p); } queue.print(); System.out.println("====="); while(queue.size() > 0){ queue.remove(); queue.print(); System.out.println("====="); } } }
结果:
Person [name=zhang0, sex=m] Person [name=zhang1, sex=m] Person [name=zhang2, sex=m] Person [name=zhang3, sex=m] Person [name=zhang4, sex=m] Person [name=zhang5, sex=m] Person [name=zhang6, sex=m] Person [name=zhang7, sex=m] Person [name=zhang8, sex=m] Person [name=zhang9, sex=m] ===== Person [name=zhang0, sex=m] Person [name=zhang1, sex=m] Person [name=zhang2, sex=m] Person [name=zhang3, sex=m] Person [name=zhang4, sex=m] Person [name=zhang5, sex=m] Person [name=zhang6, sex=m] Person [name=zhang7, sex=m] Person [name=zhang8, sex=m] ===== Person [name=zhang0, sex=m] Person [name=zhang1, sex=m] Person [name=zhang2, sex=m] Person [name=zhang3, sex=m] Person [name=zhang4, sex=m] Person [name=zhang5, sex=m] Person [name=zhang6, sex=m] Person [name=zhang7, sex=m] ===== Person [name=zhang0, sex=m] Person [name=zhang1, sex=m] Person [name=zhang2, sex=m] Person [name=zhang3, sex=m] Person [name=zhang4, sex=m] Person [name=zhang5, sex=m] Person [name=zhang6, sex=m] ===== Person [name=zhang0, sex=m] Person [name=zhang1, sex=m] Person [name=zhang2, sex=m] Person [name=zhang3, sex=m] Person [name=zhang4, sex=m] Person [name=zhang5, sex=m] ===== Person [name=zhang0, sex=m] Person [name=zhang1, sex=m] Person [name=zhang2, sex=m] Person [name=zhang3, sex=m] Person [name=zhang4, sex=m] ===== Person [name=zhang0, sex=m] Person [name=zhang1, sex=m] Person [name=zhang2, sex=m] Person [name=zhang3, sex=m] ===== Person [name=zhang0, sex=m] Person [name=zhang1, sex=m] Person [name=zhang2, sex=m] ===== Person [name=zhang0, sex=m] Person [name=zhang1, sex=m] ===== Person [name=zhang0, sex=m] ===== =====
六、几种简单的线性结构介绍完了,在实际的应用环境中需要参考各种数据结构的特点来选择。
数组:查找速度很快,但长度固定,增,删效率较低。
链表:增删效率较高,长度不固定,但查找需要从头遍历整个链表,效率较低。
队列:可用数组,链表实现,先进先出。
栈:可用数组,链表实现,先进后出。