Java数据结构与算法_线性表_顺序表与链表
文章目录
- 线性表
- 顺序表
- 顺序表API设计
- 顺序表的代码实现
- 链表
- 单向链表
- 双向链表
- 总结
线性表
概述
- 线性表是最基本、最简单、也是最常用的一种数据结构。
- 一个线性表是n个具有相同特性的数据元素的有限序列。
先驱元素: 若A元素在B元素的前面,则称A为B的前驱元素
后继元素: 若B元素在A元素的后面,则称B为A的后继元素
线性表的特征: 数据元素之间具有一种“一对一”的逻辑关系。
- 第一个数据元素没有前驱,这个数据元素被称为头结点;
- 最后一个数据元素没有后继,这个数据元素被称为尾结点;
- 除了第一个和最后一个数据元素外,其他数据元素有且仅有一个前驱和一个后继
线性表的分类:
线性表中数据存储的方式可以是顺序存储,也可以是链式存储,按照数据的存储方式不同,可以把线性表分为顺序
表和链表。
顺序表
概述:
- 顺序表是在计算机内存中以数组的形式保存的线性表
- 线性表的顺序存储是指用一组地址连续的存储单元,依次存储线性表中的各个元素、使得线性表中再逻辑结构上响铃的数据元素存储在相邻的物理存储单元中
- 即通过数据元素物理存储的相邻关系来反映数据元素之间逻辑上的相邻关系。
顺序表API设计
顺序表类名SequenceList:
- 构造方法:SequenceList(int capacity):创建容量为capacity的SequenceList对象
- 成员变量:
1.private T[] eles:存储元素的数组
2.private int N:当前线性表的长度 - 成员方法
1.public void clear():空置线性表
2.publicboolean isEmpty():判断线性表是否为空,是返回true,否返回false
3.public int length():获取线性表中元素的个数
4.public T get(int i):读取并返回线性表中的第i个元素的值
5.public void insert(int i,T t):在线性表的第i个元素之前插入一个值为t的数据元素。
6.public void insert(T t):向线性表中添加一个元素t
7.public T remove(int i):删除并返回线性表中第i个数据元素。
8.public int indexOf(T t):返回线性表中首次出现的指定的数据元素的位序号,若不存在,则返
回-1.
顺序表的代码实现
import java.util.Iterator;public class SequenceList<T> implements Iterable<T>{//存储元素的数组private T[] eles;//记录当前顺序表中的元素个数private int N;//构造方法public SequenceList(int capacity){//初始化数组this.eles=(T[])new Object[capacity];//初始化长度this.N=0;}//将一个线性表置为空表public void clear(){this.N=0;}//判断当前线性表是否为空表public boolean isEmpty(){return N==0;}//获取线性表的长度public int length(){return N;}//获取指定位置的元素public T get(int i){return eles[i];}//向线型表中添加元素tpublic void insert(T t){if (N==eles.length){resize(2*eles.length);}eles[N++]=t;}//在i元素处插入元素tpublic void insert(int i,T t){if (N==eles.length){resize(2*eles.length);}//先把i索引处的元素及其后面的元素依次向后移动一位for(int index=N;index>i;index--){eles[index]=eles[index-1];}//再把t元素放到i索引处即可eles[i]=t;//元素个数+1N++;}//删除指定位置i处的元素,并返回该元素public T remove(int i){//记录索引i处的值T current = eles[i];//索引i后面元素依次向前移动一位即可for(int index=i;index<N-1;index++){eles[index]=eles[index+1];}//元素个数-1N--;if (N<eles.length/4){resize(eles.length/2);}return current;}//查找t元素第一次出现的位置public int indexOf(T t){for(int i=0;i<N;i++){if (eles[i].equals(t)){return i;}}return -1;}//根据参数newSize,重置eles的大小public void resize(int newSize){//定义一个临时数组,指向原数组T[] temp=eles;//创建新数组eles=(T[])new Object[newSize];//把原数组的数据拷贝到新数组即可for(int i=0;i<N;i++){eles[i]=temp[i];}}@Overridepublic Iterator<T> iterator() {return new SIterator();}private class SIterator implements Iterator{private int cusor;public SIterator(){this.cusor=0;}@Overridepublic boolean hasNext() {return cusor<N;}@Overridepublic Object next() {return eles[cusor++];}}
}
//测试环节
public class SequenceListTest {public static void main(String[] args) {//创建顺序表对象SequenceList<String> sl = new SequenceList<>(10);//测试插入sl.insert("王仙芝");sl.insert("剑九黄");sl.insert("李淳罡");sl.insert(1,"徐凤年");for (String s : sl) {System.out.println(s);}//测试获取String getResult = sl.get(1);System.out.println("获取索引1处的结果为:"+getResult);//测试删除String removeResult = sl.remove(0);System.out.println("删除的元素是:"+removeResult);//测试清空sl.clear();System.out.println("清空后的线性表中的元素个数为:"+sl.length());}
}
链表
概述:
- 链表是一种物理存储单元上非连续、非顺序的存储结构,其物理结构不能只管的表示数据元素的逻辑顺序,数据元素的逻辑顺序是通过链表中的指针链接次序实现的
- 链表由一系列的结点(链表中的每一个元素称为结点)组成,结点可以在运行时动态生成。
结点API设计
类名 | Node |
---|---|
构造方法 |
Node(T t,Node next): 创建Node对象 |
成员变量 |
T item:存储数据 Node next:指向下一个结点 |
实现结点类
public class Node<T> {
//存储元素 public T item;
//指向下一个结点 public Node next; public Node(T item, Node next) {this.item = item;this.next = next; }
}
生成链表:
public static void main(String[] args) throws Exception { //构建结点 Node<Integer> first = new Node<Integer>(11, null); Node<Integer> second = new Node<Integer>(13, null); Node<Integer> third = new Node<Integer>(12, null); Node<Integer> fourth = new Node<Integer>(8, null); Node<Integer> fifth = new Node<Integer>(9, null); //生成链表 first.next = second; second.next = third; third.next = fourth; fourth.next = fifth;
}
单向链表
概述:
- 单向链表是链表的一种,它由多个结点组成,每个结点都由一个数据域和一个指针域组成,数据域用来存储数据,指针域用来指向其后继结点。
- 链表的头结点的数据域不存储数据,指针域指向第一个真正存储数据的结点。
单向链表LinkList类:
- 构造方法:LinkList():创建LinkList对象
- 成员方法:
1.public void clear():空置线性表
2.publicboolean isEmpty():判断线性表是否为空,是返回true,否返回false
3.public int length():获取线性表中元素的个数
4.public T get(int i):读取并返回线性表中的第i个元素的值
5.public void insert(T t):往线性表中添加一个元素;
6.public void insert(int i,T t):在线性表的第i个元素之前插入一个值为t的数据元素。
7.public T remove(int i):删除并返回线性表中第i个数据元素。
8.public int indexOf(T t):返回线性表中首次出现的指定的数据元素的位序号,若不存在,则
返回-1。 - 成员内部类:private class Node:结点类
- 成员变量:
1.private Node head:记录首结点
2.private int N:记录链表的长度
单向链表的代码演示
import java.util.Iterator;
public class LinkList<T> implements Iterable<T>{//记录头结点private Node head;//记录链表的长度private int N;//结点类private class Node {//存储数据T item;//下一个结点Node next;public Node(T item, Node next) {this.item = item;this.next = next;}}public LinkList() {//初始化头结点、this.head = new Node(null,null);//初始化元素个数this.N=0;}//清空链表public void clear() {head.next=null;this.N=0;}//获取链表的长度public int length() {return N;}//判断链表是否为空public boolean isEmpty() {return N==0;}//获取指定位置i出的元素public T get(int i) {//通过循环,从头结点开始往后找,依次找i次,就可以找到对应的元素Node n = head.next;for(int index=0;index<i;index++){n=n.next;}return n.item;}//向链表中添加元素tpublic void insert(T t) {//找到当前最后一个结点Node n = head;while(n.next!=null){n=n.next;}//创建新结点,保存元素tNode newNode = new Node(t, null);//让当前最后一个结点指向新结点n.next=newNode;//元素的个数+1N++;}//向指定位置i出,添加元素tpublic void insert(int i, T t) {//找到i位置前一个结点Node pre = head;for(int index=0;index<=i-1;index++){pre=pre.next;}//找到i位置的结点Node curr = pre.next;//创建新结点,并且新结点需要指向原来i位置的结点Node newNode = new Node(t, curr);//原来i位置的前一个节点指向新结点即可pre.next=newNode;//元素的个数+1N++;}//删除指定位置i处的元素,并返回被删除的元素public T remove(int i) {//找到i位置的前一个节点Node pre = head;for(int index=0;index<=i-1;i++){pre=pre.next;}//要找到i位置的结点Node curr = pre.next;//找到i位置的下一个结点Node nextNode = curr.next;//前一个结点指向下一个结点pre.next=nextNode;//元素个数-1N--;return curr.item;}//查找元素t在链表中第一次出现的位置public int indexOf(T t) {//从头结点开始,依次找到每一个结点,取出item,和t比较,如果相同,就找到了Node n = head;for(int i=0;n.next!=null;i++){n=n.next;if (n.item.equals(t)){return i;}}return -1;}@Overridepublic Iterator<T> iterator() {return new LIterator();}private class LIterator implements Iterator{private Node n;public LIterator(){this.n=head;}@Overridepublic boolean hasNext() {return n.next!=null;}@Overridepublic Object next() {n = n.next;return n.item;}}//用来反转整个链表public void reverse(){//判断当前链表是否为空链表,如果是空链表,则结束运行,如果不是,则调用重载的reverse方法完成反转if (isEmpty()){return;}reverse(head.next);}//反转指定的结点curr,并把反转后的结点返回public Node reverse(Node curr){if (curr.next==null){head.next=curr;return curr;}//递归的反转当前结点curr的下一个结点;返回值就是链表反转后,当前结点的上一个结点Node pre = reverse(curr.next);//让返回的结点的下一个结点变为当前结点curr;pre.next=curr;//把当前结点的下一个结点变为nullcurr.next=null;return curr;}
//测试代码
public static void main(String[] args) {//创建顺序表对象LinkList<String> sl = new LinkList<>();//测试插入sl.insert("王仙芝");sl.insert("剑九黄");sl.insert("李淳罡");sl.insert(1,"徐凤年");for (String s : sl) {System.out.println(s);}System.out.println("------------------------------------------");//测试获取String getResult = sl.get(1);System.out.println("获取索引1处的结果为:"+getResult);//测试删除String removeResult = sl.remove(0);System.out.println("删除的元素是:"+removeResult);//测试清空sl.clear();System.out.println("清空后的线性表中的元素个数为:"+sl.length());}}
双向链表
概述:
- 双向链表也叫双向表,是链表的一种,它由多个结点组成,每个结点都由一个数据域和两个指针域组成,数据域用来存储数据,其中一个指针域用来指向其后继结点,另一个指针域用来指向前驱结点。
- 链表的头结点的数据域不存储数据,指向前驱结点的指针域值为null,指向后继结点的指针域指向第一个真正存储数据的结点。
双向链表TowWayLinkList类 - 构造方法:TowWayLinkList():创建TowWayLinkList对象
- 成员方法:
1.public void clear():空置线性表
2.publicboolean isEmpty():判断线性表是否为空,是返回true,否返回false
3.public int length():获取线性表中元素的个数
4.public T get(int i):读取并返回线性表中的第i个元素的值
5.public void insert(T t):往线性表中添加一个元素;
6.public void insert(int i,T t):在线性表的第i个元素之前插入一个值为t的数据元素。
7.public T remove(int i):删除并返回线性表中第i个数据元素。
8.public int indexOf(T t):返回线性表中首次出现的指定的数据元素的位序号,若不存在,则
返回-1。
9.public T getFirst():获取第一个元素
10.public T getLast():获取最后一个元素 - 成员内部类:private class Node:结点类
- 成员变量:
1.private Node first:记录首结点
2.private Node last:记录尾结点
2.private int N:记录链表的长度
双向链表代码演示
import java.util.Iterator;
public class TowWayLinkList<T> implements Iterable<T> {//首结点private Node head;//最后一个结点private Node last;//链表的长度private int N;//结点类private class Node{public Node(T item, Node pre, Node next) {this.item = item;this.pre = pre;this.next = next;}//存储数据public T item;//指向上一个结点public Node pre;//指向下一个结点public Node next;}public TowWayLinkList() {//初始化头结点和尾结点this.head = new Node(null,null,null);this.last=null;//初始化元素个数this.N=0;}//清空链表public void clear(){this.head.next=null;this.head.pre=null;this.head.item=null;this.last=null;this.N=0;}//获取链表长度public int length(){return N;}//判断链表是否为空public boolean isEmpty(){return N==0;}//获取第一个元素public T getFirst(){if (isEmpty()){return null;}return head.next.item;}//获取最后一个元素public T getLast(){if (isEmpty()){return null;}return last.item;}//插入元素tpublic void insert(T t){if (isEmpty()){//如果链表为空://创建新的结点Node newNode = new Node(t,head, null);//让新结点称为尾结点last=newNode;//让头结点指向尾结点head.next=last;}else {//如果链表不为空Node oldLast = last;//创建新的结点Node newNode = new Node(t, oldLast, null);//让当前的尾结点指向新结点oldLast.next=newNode;//让新结点称为尾结点last = newNode;}//元素个数+1N++;}//向指定位置i处插入元素tpublic void insert(int i,T t){//找到i位置的前一个结点Node pre = head;for(int index=0;index<i;index++){pre=pre.next;}//找到i位置的结点Node curr = pre.next;//创建新结点Node newNode = new Node(t, pre, curr);//让i位置的前一个结点的下一个结点变为新结点pre.next=newNode;//让i位置的前一个结点变为新结点curr.pre=newNode;//元素个数+1N++;}//获取指定位置i处的元素public T get(int i){Node n = head.next;for(int index=0;index<i;index++){n=n.next;}return n.item;}//找到元素t在链表中第一次出现的位置public int indexOf(T t){Node n = head;for(int i=0;n.next!=null;i++){n=n.next;if (n.next.equals(t)){return i;}}return -1;}//删除位置i处的元素,并返回该元素public T remove(int i){//找到i位置的前一个结点Node pre = head;for(int index=0;index<i;index++){pre=pre.next;}//找到i位置的结点Node curr = pre.next;//找到i位置的下一个结点Node nextNode= curr.next;//让i位置的前一个结点的下一个结点变为i位置的下一个结点pre.next=nextNode;//让i位置的下一个结点的上一个结点变为i位置的前一个结点nextNode.pre=pre;//元素的个数-1N--;return curr.item;}@Overridepublic Iterator<T> iterator() {return new TIterator();}private class TIterator implements Iterator{private Node n;public TIterator(){this.n=head;}@Overridepublic boolean hasNext() {return n.next!=null;}@Overridepublic Object next() {n=n.next;return n.item;}}
}
//测试类
public class TowWayLinkListTest {public static void main(String[] args) {//创建双向链表对象TowWayLinkList<String> sl = new TowWayLinkList<>();//测试插入sl.insert("姚明");sl.insert("科比");sl.insert("麦迪");sl.insert(1,"詹姆斯");for (String s : sl) {System.out.println(s);} System.out.println("第一个元素是:"+sl.getFirst());System.out.println("最后一个元素是:"+sl.getLast()); //测试获取String getResult = sl.get(1);System.out.println("获取索引1处的结果为:"+getResult);//测试删除String removeResult = sl.remove(0);System.out.println("删除的元素是:"+removeResult);//测试清空sl.clear();System.out.println("清空后的线性表中的元素个数为:"+sl.length());}
总结
顺序表与链表的比较:
- 相比链表 ,顺序表的插入效率比较低,而定义数组大小也是固定的,有时候通过扩容的方法使耗时突增,如果查找的比较多,建议使用顺序表。
- 相比顺序表,链表的查询操作性能会比较低。因此,如果我们的程序中查询操作比较多,建议使用顺序表,增删操作比较多,建议使用链表。
Java数据结构与算法_线性表_顺序表与链表相关推荐
- Python数据结构与算法(2.2)——顺序表
Python数据结构与算法(2.2)--顺序表 0. 学习目标 1. 线性表的顺序存储结构 1.1 顺序表基本概念 1.2 顺序表的优缺点 1.3 动态顺序表 2. 顺序表的实现 2.1 顺序表的初始 ...
- Java数据结构和算法:线性表
线性表的定义 线性表(linear-list)是最常用最简单的一种数据结构.一个线性表是n (n≥0)个相同类型数据元素的有限序列.记为: L= (a1, a2 , - , an ). 其中,L是表名 ...
- 数据结构与算法笔记(二)—— 顺序表
一.顺序表的形式 在程序中,经常需要将一组(通常是同为某个类型的)数据元素作为整体管理和使用,需要创建这种元素组,用变量记录它们,传进传出函数等.一组数据中包含的元素个数可能发生变化(可以增加或删除元 ...
- Java数据结构和算法:HashMap,哈希表,哈希函数
1. HashMap概述 HashMap是基于哈希表的Map接口的非同步实现(Hashtable跟HashMap很像,唯一的区别是Hashtalbe中的方法是线程安全的,也就是同步的).此实现提供所有 ...
- 【Java数据结构与算法】第十章 哈希表和二叉树
第十章 哈希表和二叉树 文章目录 第十章 哈希表和二叉树 一.哈希表 1.介绍 2.代码实现 二.二叉树 1.介绍 2.遍历二叉树 3.查找二叉树 4.二叉树删除节点 5.二叉树综合实例 一.哈希表 ...
- rsa算法c语言实现_数据结构与算法之线性表-顺序表实现(C语言版本)
原文托管在Github: https://github.com/shellhub/blog/issues/52 数据结构与算法之线性表-顺序表实现(C语言版本) 前言 数据结构与算法是一个程序员必备的 ...
- mysql 线性表_数据结构-线性表之顺序表
线性表 (1)逻辑结构和物理结构 物理结构:数据元素在内存中真实的存放次序,有可能是连续存放的,也可能是散落于内存里. 逻辑结构:为了便于描述数据元素之间的关系,我们想象出数据之间应该有某种的对应关系 ...
- 黑马程序员 C语言数据结构与算法之线性表(链表/栈/队列/顺序表)
C语言 链表基础知识清晰讲解(黑马) 讲的蛮好,就是音质不太好,有时听不清讲的啥! [黑马]数据结构与算法之线性表(链表/栈/队列/顺序表)[配套源码 嘛蛋,看错了,这是java的... 文章目录 链 ...
- java数据结构与算法之顺序表与链表深入分析
转载请注明出处(万分感谢!): http://blog.csdn.net/javazejian/article/details/52953190 出自[zejian的博客] 关联文章: java数据结 ...
最新文章
- [蓝桥杯][算法提高VIP]断案-枚举
- ConvLab介绍及使用
- 【每日SQL打卡】​​​​​​​​​​​​​​​DAY 8丨平面上的最近距离【难度中等】
- 安远职业高中计算机专业,安远中等专业学校2021年招生简章
- nohup rabbitmq python
- python 基本数据类型之列表
- python有哪些用途-Python能用来做什么?以下是Python的三大主要用途
- POJ 3126 Prime Path 简单广搜(BFS)
- Centos之故障排除
- 一文搞懂SPI通信协议
- 在线绘制网络拓扑图操作方法分享
- 平面离散点集Delaunay三角化
- 使用Flutter实现仿微信录音的插件
- 【PAC集成电机控制芯片】了解PAC集成电机控制芯片
- 动态规划(pta例题)
- 【详解】SPI中的极性CPOL和相位CPHA是什么以及如何设置
- IDEA如何创建web项目
- 越来越庸俗的“感动中国”
- PCB布线时应该注意的问题
- 【资讯】福布斯:旅行积分计划是区块链主要目标,对旅行者来说是好消息