首页 > 代码库 > 线性表
线性表
线性表(顺序存储、链式存储):一对一松耦合关系。(List就是线性表的意思)
基本特征(非空、有限的线性表)
- 首位元素唯一
- 除最后一个元素外,每个元素只有一个后继元素
- 除第一个元素外,每个元素只有一个前驱元素
基本操作:
- 初始化(构造器、创建空的线性表)
- 返回长度(元素个数)
- 获取指定索引处的元素
- 查找数据元素的索引 (仅仅返回找到的第一个,没找到则返回-1)
- 指定位置插入元素(长度+1)
- 尾部插入元素(长度+1)
- 删除指定位置的元素(长度-1)
- 删除尾部的元素(长度-1)
顺序结构:SequenceList
- 逻辑地址和物理地址一致(逻辑上连续表现为物理地址上的连续)
- 地址的计算 : an=a0+nb; (b表示每个元素的存储单元大小)
- 从2的公式看的出访问表中任意一个元素不存在时间上时间上的差异,即顺序结构可以实现随机访问(查找快)
- 增删比较麻烦(操作决定它要腾挪和变化容量)
------------------------------------------------------------------------------------------------------------------------
链式结构:LinkList
1. 不能随机访问
2. 插入删除效率比较高
顺序结构实现
import java.util.Arrays;public class SequenceList<T> { private final int DEFAULT_SIZE = 16; //定义一个常量 private int capacity = DEFAULT_SIZE; //保存数组的容量 private Object[] elementData; //用数组实现 private int size=0; //数组当前元素个数 public SequenceList() //1.创建一个链表并且初始化 { elementData = new Object[capacity]; } public SequenceList(T element)//以一个元素为基础创建链表 { this(); elementData[0]=element; size++; } public SequenceList(int initSize) //指定初始容量 { //最好要先判断一个传进来的参数 //指定的容量是2的n次方 capacity = 1; while(capacity<initSize) { capacity<<=1; } elementData = new Object[capacity]; } public int Length() //2.获取list的大小 { return size; } public T get(int index) //3.获取指定索引处的元素 { //传进来的参数一定要判断其合法性 if(index<0 || index>size-1) { throw new IndexOutOfBoundsException("数组下标越界"); } return (T)elementData[index]; } public int indexOf(T element) //4.查找指定元素的索引 { for(int i=0;i<capacity;i++) { if(element.equals(elementData[i])) { return i; } } return -1; } public void insert(T element,int index) //5.在指定位置插入一个元素 { if(index<0 || index>size) { throw new IndexOutOfBoundsException("数组下标越界"); } //先处理数组长度问题,保证数组长度增加后仍然安全 if((size+1)>capacity) { //容量不够了,扩容,把原数组copy到新数组 while(capacity<(size+1)) { capacity <<=1; } elementData = Arrays.copyOf(elementData, capacity); //效率不好 } //把index处的数组元素后移 System.arraycopy(elementData,index,elementData,index+1,size-index); elementData[index]=element; size++; } public void insertLast(T element) //6.在尾部新增一个元素 { insert(element,size); //注意尾部是size而不是capacity } public T remove(int index) //7.删除指定位置的元素 { if(index<0 || index>size-1) { throw new IndexOutOfBoundsException("线性表索引越界"); } T oldValue = (T)elementData[index]; int numMoved = size - index - 1; //index后面多少个元素都要前移 if(numMoved>0) { System.arraycopy(elementData, index+1, elementData, index, numMoved); } elementData[--size] = null; return oldValue; } public T removeLast() //8.删除尾部的元素 { return remove(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()+", ");//逗号+空格 } //删除最后一个“逗号和空格”,加上"]" [3,4,5, int length = sb.length(); return sb.replace(length-2, length, "]").toString(); } } }
单链表
public class LinkList<T> { //内部类Node代表节点 private class Node { private T data; //保存节点的数据 private Node next; //指向下一个节点 public Node(){} public Node(T data, LinkList<T>.Node next) { super(); this.data =http://www.mamicode.com/ 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) //根据索引获取某元素的数据 { if(index<0 || index>size-1) { throw new IndexOutOfBoundsException("链表越界"); } Node current = header; for(int i=0;current!=null && i<size;i++) { if(i == index) { return current.data; } } current = current.next; return null; } public int indexOf(T element) //获取链表中指定元素的索引 { Node current = header; for(int i=0;i<size && current!=null;i++ , current=current.next ) //要返回索引所以必须在循环里也写上i { 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) //如果还是空链表 { addAtLast(element);//尾插法 } else { //获取插入的前一个节点 Node pre = header; for(int i=0;i<index-1;i++) { pre=pre.next; } pre.next = new Node(element,pre.next); //让新节点只想原来pre.next节点 size++; } } private void addAtLast(T element) //尾插法--被insert(T,int)调用 { header = new Node(element,null); tail = header; //只有一个节点,header和tail都指向它 size++; } public void addAtHeader(T element)//头插法 { //总是以新节点作为头结点 header = new Node(element,header); //不管原来的头结点是否为空 size++; } public T delete(int index) //删除链式表指定处的元素 { if(index<0 || index>size-1) { throw new IndexOutOfBoundsException("链表索引错误"); } //删除头节点有点特殊 Node del = header; if(index == 0) { header = header.next; del.next=null; //让原来的头结点的下一个指向null //del = null; //让原来的头结点失去引用 } else { Node pre = header; for(int i =0;i<index-1;i++) //让pre指向index-1节点 { pre = pre.next; } del = pre.next; //del指向了index pre.next = pre.next.next; del.next=null; //让需要删除的节点的下一指向指向null } size--; return del.data; } public T deleteLast() //删除最后一个元素 { return delete(size-1); } public boolean empty() //判断链表是否为空 { return size ==0; } public void clear() //清空链表 { // Node pre =header; Node current = pre.next; for(;current!=null;current =current.next) { pre.next = null; pre = current; } //pre.next = 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.replace(len-2, len, "]").toString(); } }}
循环链表(circular linked list)---无头无尾链表 (从链表中任一节点出发均可以找到表中其他所有节点)
(算法实现更容易,让tail.next = header即可)
(头插法和尾插法均可)
(当使用单链表比较麻烦的时候,可以考虑这种实现)
双向链表(double linked list------DbLinkedList)
保存前驱引用和后继引用,所以维护成本略大
public class DbLinkedList<T> { private class Node //内部节点类 { private T data; private Node prev; private Node next; public Node(){} public Node(T data, Node prev, DbLinkedList<T>.Node next) { super(); this.data =http://www.mamicode.com/ data; this.prev = prev; this.next = next; } } private Node header; //保存该链表的头结点 private Node tail; //保存链表的尾节点 private int size; //包含链表中已包含的节点数 public DbLinkedList() { //空链表的header 和 tail都是null header = null; tail = null; } public DbLinkedList(T element) //以特定的元素构建链表 { header = new Node(element,null,null); //只有一个节点,header,tail都指向该节点 tail = header; size++; } public int length()//返回链表的长度 { return size; } public T get(int index)//获取链式线性表中索引为index处的元素 { return getNodeByIndex(index).data; } private Node getNodeByIndex(int index) //根据索引获取 { if(index<0 || index>size-1) { throw new IndexOutOfBoundsException("线性表下标越界"); } if(index<=size/2) { //header节点开始 Node current = header; for(int i=0;i<size/2&¤t!=null; i++,current=current.next)//索引靠前就用 { if(i==index) { return current; } } } else { //从tail节点开始搜索 Node current = tail; for(int i=size-1;i>size/2&¤t!=null; i--,current=current.prev) { if(i == index) { return current; } } } return null; } public int indexOf(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) { addLast(element); //尾插法 } else { //当index为0的时候,也就是在表头插入 if(index==0) { addAtHeader(element); } else //中间插入 { Node prev = getNodeByIndex(index-1); //获取插入节点的前一个节点 Node next = prev.next; //获取插入节点 Node newNode = new Node(element,prev,next); prev.next = newNode; next.prev = newNode; size++; } } } public void addLast(T element) //尾插法实现 { if(header == null) { header = new Node(element,null,null); tail = header; } else { //找到尾节点 Node newNode = new Node(element,tail,null); tail.next = newNode; tail = newNode; } size++; } public void addAtHeader(T element) //采用头插法 { //创建新节点的next指向header,并把它作为新的list头 header = new Node(element,null,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; //让head指向原来的header的next header.prev = null; //新header的prev指向null } else { Node prev = getNodeByIndex(index-1); //获取要删除的前一个节点 del = prev.next; //获取要删除的元素 //开始处理互相引用 prev.next = del.next; if(del.next!=null) { del.next.prev = prev; } del.prev = null; del.next = null; } size--; return del.data; } public T deleteLast() //删除链式线性表中的最后一个元素 { return delete(size-1); } public boolean empty() //判断是否为空 { return size==0; } public void clear() { //前向和后项全部要置为null } 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.replace(len-2, len, "]").toString(); } } public String reverseToString() { if(empty()) { return "[]"; } else { StringBuilder sb = new StringBuilder("["); for(Node current = tail;current!=null;current = current.prev) { sb.append(current.data.toString()+", "); } int len=sb.length(); return sb.replace(len-2,len, "]").toString(); } }}
小结:线性表就是加强操作的动态数组,充当容器的工具类。
Java中的实现(ArrayList,LinkedList,其中LinkedList还是双向链表)
线性表
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。