线性表
应用程序中的数据大致有如下4类基本的逻辑结构:
集合:数据元素之间只有“同属于一个集合”关系。
线性结构:数据元素之间存在一个对一个的关系。
树性结构:数据元素之间存在一个对多个的关系。
图状结构或网状结构:数据元素之间存在多个对多个的关系。
对于数据不同的逻辑结构,计算机在物理磁盘上通常有2种物理存储结构:
顺序存储结构
链式存储结构
线性表
对于常用数据结构,可以简单分为线性结构和非线性结构,其中线性结构主要是线性表,而非线性结构主要是树和图。
线性表(Linear List)是由n(n >= 0)个数据元素a1,a2,a3...,an组成的有限序列。线性表中每个元素必须具有相同的结构。
线性表中的元素可以是一个数据值,也可以是一个对象
关于线性表还可有如下定义:
线性表中包含的数据元素个数n称为表的长度,长度为0时该表也被称为分表
当n>0时,表可表示为(a1,a2,a3...,an)
对于一个非空的、有限的线性表而言,总是具有如下特征:
总是存在唯一的“第一个”数据元素
总存在唯一的“最后一个”数据元素
除第一个数据元素外,集合中的每一个数据元素都只有一个前驱的数据元素
除最后一个数据元素外,集合中的每一个数据元素都只有一个后继的数据元素
线性表的基本操作:
初始化:通常是一个构造器,用于创建一个空的线性表
返回线性表的长度:该方法用于返回线性表中数据元素的个数
获取指定所引出的元素:根据索引返回线性表中的数据元素
按值查找数据元素的位置:如果线性表中存在一个或错个与查找值相等的数据元素,该方法返回第一个搜索值相等的数据元素的索引,否则返回-1
直接插入数据元素:向线性表的头部插入一个数据元素,线性表长度+1
向指定元素插入数据元素:向线性表的指定位置插入一个数据元素,线性表长度+1
直接删除数据元素:
删除线性表中指定位置的数据元素:
判断线性表是否为空:
清空线性表:
顺序存储结构
线性表的顺序存储结构指用一组地址连续的存储单元依次存放线性表的元素。换句话说,顺序结构线性表中数据元素的物理关系和逻辑关系是一致的

package com.test_one; import java.util.Arrays; import static java.util.Arrays.*; /** * Created by Administrator on 2017/3/6. */ public class SequenceList<T> { private int DEFAULT_SIZE = 16; private int capacity; private Object[] elementData; private int size = 0; public SequenceList(){ capacity = DEFAULT_SIZE; elementData = new Object[capacity]; } public SequenceList(T element){ this(); elementData[0] = element; size++; } public SequenceList(T element , int initSize){ capacity = 1; while(capacity < initSize){ capacity <<= 1; } elementData = new Object[capacity]; elementData[0] = element; size++; } public int length(){ return size; } public T get(int i){ if(i <0 || i > size -1){ throw new IndexOutOfBoundsException("线性表索引越界"); } return (T)elementData[i]; } public int locate(T element){ for(int i = 0; i < size ; i++){ if(elementData[i].equals(element)){ return i; } } return -1; } public void insert(T element , int index){ if(index <0 || index > size){ throw new IndexOutOfBoundsException("线性表索引越界"); } ensureCapacity(size + 1); System.arraycopy(elementData , index , elementData , index+1 , size - index); elementData[index] = element; size++; } public void add(T element){ insert(element , size); } public void ensureCapacity(int minCapacity){ if(capacity < minCapacity){ capacity = 1; while(capacity < minCapacity){ capacity <<= 1; } elementData = copyOf(elementData , capacity); } } public T delete(int index){ if(index < 0 || index > size -1){ throw new IndexOutOfBoundsException("线性表越界"); } T oldValue = (T)elementData[index]; int numMoved = size - index - 1; if(numMoved > 0){ System.arraycopy(elementData , index + 1 , elementData , index , numMoved); } elementData[--size] = null; return oldValue; } public T remove(){ return delete(size - 1); } public boolean empty(){ return size == 0; } public void clear(){ Arrays.fill(elementData , null); size = 0; } public String toString(){ if(size == 0){ return "[]"; }else{ StringBuilder sb = new StringBuilder("["); for(int i = 0; i < size; i++){ sb.append(elementData[i].toString() + ", "); } int len = sb.length(); return sb.delete(len - 2 , len).append("]").toString(); } } }
public class SequenceListTest { public static void main(String[] args){ SequenceList<String> list = new SequenceList<String>(); list.add("aaaa"); list.add("bbbb"); list.add("cccc"); list.insert("dddd" , 1); System.out.println(list); list.delete(2); System.out.println(list); System.out.println("cccc在线性表中的位置:" + list.locate("cccc")); } }
链式存储结构
链式存储结构的线性表(也被简称为链表)将采用一组地址任意的存储单元存放线性表中的数据元素。链式结构的线性表不会按线性的逻辑顺序来保存元素,它需要在每一个数据元素里保存一个引用下一个数据元素的引用(或者叫指针)。


单链表上的基本运算:
单链表指的是每一个节点只保留一个引用,该引用指向当前节点的下一个节点,没有引用指向头节点,为节点的next引用为null
建立单链表有一下两种方式:
头插法建表:
尾插法建表:
头插法虽然算法简单,但声称链表节点次序相反,希望二者次序一致应该使用尾部插法建立链表

package com.test_one; /** * Created by Administrator on 2017/3/6. */ public class LinkList<T> { 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 LinkList(){ header = null; tail = null; } public LinkList(T element){ header = new Node(element , null); tail = header; size++; } public int length(){ return size; } public T get(int index){ return getNodeByIndex(index) == null ? null :getNodeByIndex(index).data; } public Node getNodeByIndex(int index){ if(index <0 || index > size -1){ throw new IndexOutOfBoundsException("线性表索引越界"); } Node current = header; for(int i = 0; i < size && current != null; i++ , current = current.next){ if(i == index){ return current; } } return null; } public int locate(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 insert(T element , int index){ if(index < 0 || index > size ){ throw new IndexOutOfBoundsException("线性表索引越界"); } if(header == null){ add(element); }else { if(index == 0){ addAtHeader(element); }else{ Node prev = getNodeByIndex(index - 1); prev.next = new Node(element , prev.next); size++; } } } public void add(T element){ if(header == null){ header = new Node(element , null); tail = header; }else{ Node newNode = new Node(element , null); tail.next = newNode; tail = newNode; } size++; } public void addAtHeader(T element){ header = new Node(element , header); if(tail == null){ tail = header; } size++; } public T delete(int index){ if(index < 0 || index > size -1){ throw new IndexOutOfBoundsException("线性表索引越界"); } Node del = null; if(index == 0){ del = header; header = header.next; }else{ Node prev = getNodeByIndex(index -1); del = prev.next; prev.next = del.next; del.next = null; } size--; return del.data; } public boolean empty(){ return size == 0; } public void clear(){ header = null; tail = null; size = 0; } public String toString(){ if(empty()){ return "[]"; }else{ StringBuilder sb = new StringBuilder("["); for(Node current = header; current != null; current = current.next){ sb.append(current.data.toString() +", "); } int len = sb.length(); return sb.delete(len - 2 , len).append("]").toString(); } } }
package com.test_one; /** * Created by Administrator on 2017/3/6. */ public class LinkListTest { public static void main(String[] args){ LinkList<String> list = new LinkList<String>(); list.insert("aaaa" , 0); list.add("bbbb"); list.add("cccc"); list.insert("dddd" , 1); System.out.println(list); list.delete(2); System.out.println(list); System.out.println("cccc在链表中的位置:" + list.locate("cccc")); System.out.println("链表中索引2处的元素:" + list.get(2)); } }
循环链表
循环链表是一种守卫相接的链表。将单链表的尾节点next指针改为引用单链表header节点,这个单链表就成了循环链表

双向链表
如果每个节点包里有两个引用prev和next,让prev指向当前节点的上一个节点,让next纸箱当前节点的下一个节点。这样的形成的链表被称为双向链表。

双向链表的查找:
根据被搜索的index的值判断它更靠近header,还是更靠近tail。更靠近哪边从哪边开始搜索。

线性表的实现分析:
顺序表:
空间性能:顺序表的存储空间是静态分布的,需要一个长度固定的数组,因此总有部分数组元素被浪费
时间性能:顺序表中元素的逻辑顺序与物理存储顺序保持一致,而且支持随机存取。因此顺序表在查找、读取时性能很好。
链表:
空间性能:链表的存储空间是动态分布的,因此不会空间被浪费。但由于链表也需要额外的空间来为每个节点保存指针,因此也要牺牲一部分孔家
时间性能:链表采用链式结构来保存表内元素,因此在插入、删除元素时性能较好。

浙公网安备 33010602011771号