大家好,欢迎来到IT知识分享网。

一、什么是线性表
线性表是其组成元素间具有线性关系的一种线性结构,是由n个数据类型相同的元素构成的有限序列。其具有“一对一”的逻辑关系,与位置有关,除了头尾元素之外,每一个元素都有唯一的前驱元素和后继元素,即元素ai前面的元素为ai-1,后面的元素为ai+1。
线性表就是数组的一种特殊储存方式:从头到尾依次储存数据.
线性表数据结构的特征:
- 有且只有一个“首元素”
- 有且只有一个“末元素”
- 除末元素之外,其余元素均有唯一的后继元素
- 除首元素之外,其余元素均有唯一的前驱元素
对于线性表,主要可以进行以下操作:
- 添加结点
- 插入结点
- 删除结点
- 查找结点
- 遍历结点
- 统计结点数
public interface IList { public void insert(int index,Object data) throws Exception; //在指定位置插入元素 public void clear(); //清空线性表 public void remove(int index); //删除指定位置元素 public boolean isEmpty(); //判断线性表是否为空 public Object get(int index); //获取指定位置元素 public int length(); //获取线性表长度 public int indexOf(Object data); //获取指定元素的角标 public void display(); //输出线性表中所有元素 }
二、操作顺序表
线性表的顺序存储结构,是把线性表中的所有元素按照其逻辑顺序,依次存储到计算机在内存中指定的一块连续存储空间中,成为顺序表。顺序储存结构是用数组来保存数据的,所有数据元素的存储位置均取决于第一个数据元素的存储位置。

元素在内存中的物理存储位置和他们在线性表中的逻辑位置一致。
所有数据元素的存储位置均取决于第一个数据元素的存储位置。
顺序表的特点:
- 在线性表中逻辑上相邻的元素在物理存储位置上也相邻;
- 可按照数据元素的索引号进行随机存取,时间复杂度为O(1);
- 插入、删除操作需要移动大量的元素,时间复杂度为O(n);
- 需要预先分配存储空间,可能会造成空间浪费,但存储密度高,数据紧凑。
顺序表的操作
- 定义顺序队列结构
- 初始化队列
- 获取队列状态
- 入队操作
- 出队操作
- 获取队头元素
public class SqList implements IList { private Object[] listItem; //顺序表的存储空间大小; private int curLen; //顺序表的当前长度 private int maxSize; //顺序表的最大尺寸 //构造最大尺寸为maxSize的顺序表 SqList(int maxSize){ this.maxSize = maxSize; this.curLen = 0; this.listItem = new Object[maxSize]; } //在第index的位置插入数据data public void insert(int index, Object data) throws Exception{ if(curLen == maxSize) //判断存储空间是否已满 throw new Exception("数组已满,无法插入!"); if(index<0||index>curLen) //判断插入位置是否合法 throw new IndexOutOfBoundsException("所插入的位置不在索引范围!"); for(int i=curLen;i>index;i--) { //将插入位置后面的所有元素后移一位 listItem[i]=listItem[i-1]; } listItem[index] = data; //插入数据 curLen++; //表长+1 } //清空顺序表 public void clear() { curLen = 0; } //删除顺序表中指定位置index处的数据 public void remove(int index) throws IndexOutOfBoundsException{ if(index<0||index>curLen) //判断位置是否合法 throw new IndexOutOfBoundsException("当前索引不存在!"); for(int i=index;i<curLen;i++) { //将指定位置之后的元素均前移一位 listItem[i] = listItem[i+1]; } curLen--; //表长-1 } //判断顺序表是否为空 public boolean isEmpty() { return curLen == 0; } //获取交表为index处的数据 public Object get(int index) throws IndexOutOfBoundsException{ if(index<0||index>curLen) throw new IndexOutOfBoundsException("当前索引不存在!"); return listItem[index]; } //返回顺序表长度 public int length() { return curLen; } //获取元素在顺序表中的位置 public int indexOf(Object data) { for(int i=0;i<curLen;i++) { if(listItem[i] == data) return i; } return -1; } //显示顺序表中的元素 public void display() { for(int i=0;i<curLen;i++) System.out.print(listItem[i]); } }
顺序表的总结:
三、操作链表
采用链式存储结构的线性表成为链表,是用若干地址分散的存储单元存储数据元素,逻辑上相邻的数据元素在物理位置上不一定相邻,因此,链表在数据结构上分为两部分,一部分存储数据,成为数据域;一部分存储下一个元素的内存地址,成为指针域。
单链表
单链表是指节点中只包含一个指针域的链表,指针域存储指向后继结点的指针。头指针为单链表的起始地址,为单链表的唯一标识。尾指针没有后继结点,其后继结点为null,可以作为单链表结束的判定标识。
为方便操作,一般会有一个头结点,头指针的数据域为空,指针域指向第一个结点,当头结点的指针域为null是位空表。

单链表结点的存储空间是在插入和删除的过程中动态生成和释放的,不需要预先分配空间,从而避免了空间分配的不足和过剩。同时,单链表在插入和删除节点时不需要移动数据,所以其插入和删除效率较高。
结点类
public class Node { public Object data; //数据域 public Node next; //指针域 public Node(){ this(null,null); } public Node(Object data){ this(data,null); } public Node(Object data,Node next){ this.data = data; this.next = next; } }
链表的操作:
- 定义链表的结构
- 添加结点至尾部
- 添加结点至首部
- 插入结点
- 查找结点
- 删除结点
- 链表的长度
- 测试链表操作
package ch02; import java.util.Scanner; public class LinkList implements IList{ public Node head; //单链表头指针 public LinkList() { head = new Node(); } public LinkList(int n,boolean order) { this(); if(order) creat1(n); else creat2(n); } //头插法——读入的数据顺序与结点顺序相反 public void creat1(int n) { Scanner sc = new Scanner(System.in); for(int i=0;i<n;i++) { try { insert(0, sc.next()); } catch (Exception e) { e.printStackTrace(); } } } //尾插法——读入的数据顺序与结点顺序相同 public void creat2(int n) { Scanner sc = new Scanner(System.in); for(int i=0;i<n;i++) { try { insert(length(), sc.next()); } catch (Exception e) { e.printStackTrace(); } } } //向单链表插入数据 public void insert(int index, Object data) throws Exception { Node preNode = head; int preIndex; for(preIndex=-1;preIndex<index-1&&preNode!=null;preIndex++) { //查找所插入位置的前驱结点 preNode = preNode.next; } if(preIndex>index-1||preNode==null) //操作不合法则抛出异常 throw new Exception("非法操作!"); Node newNode = new Node(data); //创建新插入的结点对象 newNode.next = preNode.next; //更新指针域指向 preNode.next = newNode; } //清空单链表 public void clear() { head.data = null; head.next = null; } //删除节点 public void remove(int index) throws IndexOutOfBoundsException{ Node preNode = head; int preIndex; for(preIndex=-1;preIndex<index-1&&preNode!=null;preIndex++) { //查找待删除元素的前驱结点 preNode = preNode.next; } if(preIndex>index-1||preNode==null) //操作不合法则抛出异常 throw new IndexOutOfBoundsException(“角标越界了!”); preNode.next = preNode.next.next; } //判断单链表是否为空 public boolean isEmpty() { return head.next == null; } //获取位置index处的数据 public Object get(int index) throws IndexOutOfBoundsException { Node nextNode = head.next; int j; for(j=0;j<index&&nextNode!=null;j++) //从首结点开始查找,直到index处或nextNode为null,即查找结束 nextNode = nextNode.next; if(j>index||nextNode==null) //操作不合法则抛出异常 throw new IndexOutOfBoundsException("元素不存在!"); return nextNode.data; } //获取单链表长度 public int length() { Node nextNode = head.next; int length = 0; while(nextNode!=null) { nextNode = nextNode.next; length++; } return length; } //按值查找对应的角标 public int indexOf(Object data) { Node nextNode = head.next; int index; for(index=0;nextNode!=null;index++) { if(nextNode.data.equals(data)) return index; } return -1; } @Override public void display() { // TODO Auto-generated method stub } }
单链表插入操作
单链表插入时,只需要找到所插入位置结点的前驱结点,然后修改前驱和新插入节点的指针域即可

循环链表
循环链表就是在单链表的基础上修改而来,只是将尾结点的指针域指向了头结点,从而形成一个环状的链表。
在实现循环链表时可以用头指针或尾指针或两者同时使用来标识循环链表,通常使用尾指针来标识,可简化操作。
由于循环链表和单链表操作算法基本一致,所以不再赘述。
双向链表
双向链表即在单链表的基础上又添加了一个指针域,用来指向其前驱结点,使得在查找某个结点的前驱结点时不再需要从表头开始顺次查找,大大减小了事件复杂度,但相应的会增加内存的空间消耗。这里只写出比较核心的插入节点算法,其他算法可以参照单链表的算法自行写出。
public void insert(int i, Object x) throws Exception{ DulNode p = head; //这里没有写双向链表的节点类,读者可自行补全 int j = -1; while(p!=null&&j<i){ //寻找插入位置 p = p.next; j++; } if(j>i || p==null) throw new Exception("插入位置不合法!"); DulBode s = new DulNode(x); p.prior.next = s; s.next = p; p.prior = s; }
四、顺序表和链表的比较
优点
- 顺序表
1. 存储高效 2. 存储密度高,空间开销小 3. 实现简单,易于使用
- 链表
1.灵活,可进行空间的动态分配 2. 插入、删除效率高
缺点
- 顺序表
1. 需要预先分配空间; 2. 插入、删除操作时间复杂度高
- 链表
1.存储密度低; 2. 不存在角标,查找元素时间复杂度高
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/177517.html