线性表的Java实现
一、概念
对于常用的数据结构,可分为线性结构和非线性结构,线性结构主要是线性表,非线性结构主要是数和图。当n>0时,表可表示为:(a0,a1,a2,a3,…an)
1、 线性表的特征:
1、存在唯一的被称作”第一个”的数据元素
2、存在唯一的一个称作”最后一个的”数据元素”
3、除第一个之外,集合中的每个数据元素均只有一个前驱
4、除最后一个之外,集合中每个元素均只有一个后继
2、线性表的基本操作
1、初始化:
2、返回线性表长度
3、获取指定索引处元素
4、按值查找元素位置
5、直接插入数据元素
6、向指定位置插入元素
7、直接删除元素
8、删除指定位置元素
二、顺序存储结构
线性表的顺序结构是指用一组地址连续的存储单元依次存放线性表的元素。下面采用数组实现顺序结构线性表。
import java.util.Arrays;
public class Sequence<T> {
privateObject[] elementData;//定义一个数组
privateint DEFAULT_SIZE = 1; //数组默认大小
privateint capacity; //数组容量
privateint size = 0; //当前数组大小
//初始化
public Sequence(){
capacity= this.DEFAULT_SIZE;
elementData= new Object[capacity];
} public Sequence()(T element){
this();
elementData[0]= element;
size++;
} //返回线性表长度
public int length(){
return this.size;
} //返回指定索引处元素。
public T getElementByIndex(int index){ if(index< 0 || index > (size-1)){
System.out.println("索引范围越界!!!");
System.exit(0);
}
return (T)elementData[index];
}
//按值查找数据元素的位置
public int getIndexByValue(T value){
for(int i = 0; i < elementData.length;i++ ){
if(value.equals(elementData[i])){
return i;
}
}
return -1;//未找到则返回-1
} //向指定位置插入元素
public void insert(T element,int index){
ensureCapacity(); //确保线性表容量够
if(index>= 0 && index < size){
int i = 0;
//将插入位置之后元素挨个后移1
for(i= (size-1); i >= index;i--){
elementData[i+1]= elementData[i];
}
elementData[i+1]= element;//插入该元素
size++; //数组当前容量+1
}
else{
throw new IndexOutOfBoundsException("插入元素位置越界!!!");
}
} //想线性表末尾添加元素
public void add(T element){
ensureCapacity(); //确保线性表容量够
elementData[size]= element;
size++;
} //删除线性表中指定位置元素
public void delete(int index){
if(index>= 0 && index < size){
int i;
//将要删除元素位置之后的元素挨个前移1,通过覆盖删除
for(i= index+1;i < size;i++){
elementData[i-1]= elementData[i];
}
elementData[size-1]= null;
}
else{
thrownew IndexOutOfBoundsException("所要删除元素位置越界!!!");
}
} //删除指定元素
public void delete(T value){
int index = this.getIndexByValue(value);
if(index!= -1){
this.delete(index);
}
else{
System.out.println("您要删除的元素并不存在");
System.exit(0);
}
size--;
} //判断线性表是否为空
public boolean isEmpty(){
boolean b = false;
if(this.length()!= 0){
b= true;
}
return b;
} //清空线性表
public void clear(){
for(Object o:elementData){
o= null;
}
size= 0;
} //显示线性表中所有元素
public void view(){
System.out.print("当前线性表中元素为:");
for(int i = 0;i < size;i++){
System.out.print(elementData[i]+ " ");
}
System.out.print("\n");
} //扩充线性表容量
public void ensureCapacity(){
while((size+1)> capacity){
capacity=capacity * 2; //线性表容量每次增大一倍
elementData= Arrays.copyOf(elementData, capacity);
}
} public static void main(String[] args) {
Sequence<String> sequence = new Sequence<>();
sequence.add("hello");
sequence.add("world");
sequence.add("java");
sequence.add("perfect");
sequence.view();
sequence.insert("haha",1);
sequence.view();
System.out.println("索引为3的元素为:" +sequence.getElementByIndex(3));
System.out.println("字符串perfect的索引号为:"+ sequence.getIndexByValue("perfect"));
sequence.delete("hello");
sequence.view();
sequence.clear();
System.out.println("clear之后线性表长度为:"+ sequence.length());
}
}
三、链式存储结构
1、概念
链式存储结构的线性表(简称为链表)采用一组任意的存储单元存放线性表中的数据元素。链式存储结构的线性表不是按线性的逻辑顺序来保存数据元素,它需要在每个数据元素里保存一个引用下一个数据元素的引用。
节点 = 数据元素 + 引用下一个节点的引用 + 引用上一个节点的引用
2、单链表基本操作
建立单链表方法:1头插法建表 2尾插法建表
查找操作:1按index查找指定数据元素 2在链表中查找指定的数据元素的index
插入操作:在第index个索引处插入元素
删除操作:删除第index个节点
3、单链表具体实现
public class LinkList<T>{
//定义Node节点
private class Node{
private T data;
private Node next; public Node(){ }
public Node(T element,Node next){
this.data= element;
this.next= next;
}
}
//成员变量
private Node header;//头节点
private Node tail; //尾节点
private int size = 0; //链表长度 public LinkList(){
header= null;
tail= header;
} public LinkList(T element){
header= new Node(element,null);
tail= header;
} //获取链表中指定索引处的元素
public T get(int index){
return this.getNodeByIndex(index).data;
} //获取链表中指定索引处Node
public Node getNodeByIndex(int index){
this.checkBorder(index);
Node currentNode = header;
for(int i = 0;i < size && currentNode !=null;i++,currentNode =currentNode.next){
if(i== index){
return currentNode;
}
}
return null;
} //向指定索引处插入元素
public void insert(T element,int index){
this.checkBorder(index);
if(index== 0){
this.addAtHeader(element);
}
else{
NodeprevNode =this.getNodeByIndex(index-1);//获取插入位置的前向Node
prevNode.next=new Node(element,prevNode.next);
}
size++;
} //删除指定索引处Node
public T delete(int index){
this.checkBorder(index);
Nodedel = null;
//删除的是header
if(index== 0){
del= header;
header= header.next;
}
else{
NodeprevNode =this.getNodeByIndex(index);
del= prevNode.next;
prevNode.next= del.next; //将prevNode的后向Node设置为del.next
del.next= null;
}
size--;
returndel.data;
} //头插法向链表中添加元素
public void addAtHeader(T element){
header= new Node(element,header);//将新添加的Node的next设置为原先的header,然后将新的Node设置为新的header
if(tail==null){
tail= header;
}
size++;
} //尾插法
public void add(T element){
//链表为空的情况
if(header==null){
header= new Node(element,null);
tail= header;
}
else{
tail.next= new Node(element, null); //将tail节点的next设置为new Node
tail= tail.next;//将new Node设置为tail
}
size++;
}
//遍历整个链表
public void view(){
NodecurrentNode = header;
System.out.print("当前链表元素:");
while(currentNode!=null){
System.out.print(currentNode.data+ " ");
currentNode= currentNode.next;
}
System.out.println(""); } //检测索引是否越界
private void checkBorder(int index){
if(index< 0 || index > size-1){
thrownew IndexOutOfBoundsException("链表索引已越界");
}
} public int length(){
return this.size;
} public static void main(String args[]){
LinkList<String> linkList =new LinkList<>();
linkList.add("hello");
linkList.add("world");
linkList.addAtHeader("header");
System.out.println("当前链表长度为:"+ linkList.length());
linkList.view();
System.out.print("插入test之后,");
linkList.insert("test",2);
linkList.view();
linkList.delete(2);
System.out.print("删除索引2处元素后,");
linkList.view();
System.out.println("索引1处元素为:" +linkList.get(1));
}
}
4、双链表实现
public class DoubleLinkList<T> { //定义双向链表节点
private class Node{
private T data;
private Node prev;
private Node next;
public Node(){ }
public Node(T element,Node prev,Node next){
this.data= element;
this.prev= prev;
this.next= next;
}
} private Node header;
private Node tail;
private int size = 0; public DoubleLinkList(){
header= null;
tail= null;
} public DoubleLinkList(T element){
header= new Node(element,null,null);
tail= header;
size++;
}
//获取链表长度
public int length(){
return this.size;
} //检测index是否越界
public void checkBorder(int index){
if(index< 0 || index > size-1){
throw new IndexOutOfBoundsException("链表索引已越界");
}
} //获取指定索引处Node
public Node getNodeByIndex(int index){
checkBorder(index);//越界检测
if(index< size/2){
NodecurrentNode = header;
for(int i = 0;i < size/2;i++,currentNode = currentNode.next ){
if(i== index){
return currentNode;
}
}
}
else{
NodecurrentNode = tail;
for(int i = size-1;i >= size/2;i--,currentNode = currentNode.prev){
if(i== index){
returncurrentNode;
}
}
}
return null;
} //获取链表中指定索引处的元素值
public T get(int index){
return this.getNodeByIndex(index).data;
} //根据元素值查找元素索引
public int locate(T element){
Node currentNode = this.header;
for(int i = 0;i < size-1;i++,currentNode = currentNode.next){
if(currentNode.data.equals(element)){
returni;
}
}
return -1; } //向链表中以尾插法添加元素
public void add(T element){
if(size== 0){
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){
if(size== 0){
header= new Node(element,null,null);
tail= header;
}
else{
Node newNode =new Node(element,null,header);
header.prev= newNode;
header= newNode;
}
size++;
} //根据索引插入元素
public void insert(T element,int index){
this.checkBorder(index);
Node prevNode = this.getNodeByIndex(index-1);
Node nextNode = this.getNodeByIndex(index);
Node insertNode = new Node(element, prevNode, nextNode);
nextNode.prev= insertNode;
prevNode.next= insertNode;
size++;
} //根据索引删除元素
public void delete(int index){
this.checkBorder(index);
Node prevDelNode = this.getNodeByIndex(index-1);
Node nextDelNode = this.getNodeByIndex(index+1);
prevDelNode.next= nextDelNode;
nextDelNode.prev= prevDelNode;
size--;
} //遍历链表中元素
public void view(){
System.out.print("当前链表中元素为:");
for(int i = 0;i < size;i++){
System.out.print(this.get(i)+ " ");
}
System.out.println();
} public static void main(String[] args) {
DoubleLinkList<String> doubleLinkList =new DoubleLinkList<>();
doubleLinkList.add("hello");
doubleLinkList.add("world");
doubleLinkList.insert("test",1);
doubleLinkList.addAtHeader("first");
doubleLinkList.view();
System.out.println("索引为0处的元素值为:"+ doubleLinkList.get(0));
System.out.println("test字符串在链表中索引号为:" + doubleLinkList.locate("test"));
doubleLinkList.delete(1);
System.out.print("删除索引号为1元素后,");
doubleLinkList.view();
} }
注:本文部分内容参考自《疯狂Java程序员的基本修养》和《数据结构(C语言版)》
线性表的Java实现的更多相关文章
- 数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解
数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解 对数组有不了解的可以先看看我的另一篇文章,那篇文章对数组有很多详细的解析,而本篇文章则着重讲动态数组,另一篇文章链接 ...
- 线性表 及Java实现 顺序表、链表、栈、队列
数据结构与算法是程序设计的两大基础,大型的IT企业面试时也会出数据结构和算法的题目, 它可以说明你是否有良好的逻辑思维,如果你具备良好的逻辑思维,即使技术存在某些缺陷,面试公司也会认为你很有培养价值, ...
- 线性表(java)
线性表 概念:零个或者多个数据元素的有限序列. 特点:除了第一个元素没有前驱结点,最后一个元素没有后继结点外,其它元素有且仅有一个直接前驱和一个直接后继结点.元素的个数必定为有限个. 实现: 定义一个 ...
- 线性表的Java实现--链式存储(双向链表)
有了单向链表的基础,双向链表的实现就容易多了. 双向链表的一般情况: 增加节点: 删除节点: 双向链表的Java实现: package com.liuhao.algorithm; publi ...
- 线性表的Java实现--链式存储(单向链表)
单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始. 链式存储结构的线性表将采用一组任意的存储单元存放线性表中的数据元素.由于不需要按顺序存储,链表在 ...
- 常用数据结构-线性表及Java 动态数组 深究
[Java心得总结六]Java容器中——Collection在前面自己总结的一篇博文中对Collection的框架结构做了整理,这里深究一下Java中list的实现方式 1.动态数组 In compu ...
- 数据结构(Java描述)之线性表
基础概念 数据结构:是相互之间存在一种或多种关系的数据元素的集合. 逻辑结构和物理结构 关于数据结构,我们可以从逻辑结构和物理结构这两个维度去描述 逻辑结构是数据对象中数据元素之间的关系,是从逻辑意义 ...
- Java Se :线性表
Java的集合框架分为两个系列,Collection和Map系列.在大学期间,学习数据结构时,好像学习了线性表.非线性表.树,哎,都给忘了.其实,在Collection系列内部又可以分为线性表.集合两 ...
- Java数据结构之线性表(2)
从这里开始将要进行Java数据结构的相关讲解,Are you ready?Let's go~~ java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来的 ...
随机推荐
- Windows搭建Sublime Text 3 + Go开发环境
1. 安装Sublime Text 3 Sublime Text 3(以下简称ST)的下载与安装我就不说啦,目前还是一个测试版,不过据说比ST2增加了好多新功能,下载地址: http://www.su ...
- 【转】6.4.6 将驱动编译进Linux内核进行测试
原文网址:http://www.apkbus.com/android-98520-1-1.html 前面几节都是将Linux驱动编译成模块,然后动态装载进行测试.动态装载驱动模块不会随着Android ...
- 剑指offter-面试题7.用两个栈实现队列
题目.用两个栈实现一个队列.队列的声明如下,请实现它的两个函数appendTail和deleteHead 分别完成在对尾插入节点和在队头删除节点. 该队列类模板如下: template <typ ...
- 【转】Android LCD(四):LCD驱动调试篇
关键词:android LCD TFTSN75LVDS83B TTL-LVDS LCD电压背光电压 平台信息:内核:linux2.6/linux3.0系统:android/android4.0 平台 ...
- Scala 函数(五)
函数是一组一起执行一个任务的语句. 您可以把代码划分到不同的函数中.如何划分代码到不同的函数中是由您来决定的,但在逻辑上,划分通常是根据每个函数执行一个特定的任务来进行的. Scala 有函数和方法, ...
- Linux系统下定时上传文件至FTP服务器脚本
环境:Red Hat Enterprise Linux Server release 6.4 需求:需要将Oracle数据库的定时备份上传至FTP服务器 1.干货,用户名:oracle,数据库名称:X ...
- hdu 5627 Clarke and MST(最大 生成树)
Problem Description Clarke is a patient with multiple personality disorder. One day he turned into a ...
- STL 整理(map、set、vector、list、stack、queue、deque、priority_queue)(转)
向量(vector) <vector> 连续存储的元素<vector> Vector<int>c; c.back() 传回最后一个数据,不检查这个数据是否存在 ...
- C#常用語法糖(Csharp Syntactic sugar)
首先需要声明的是“语法糖”这个词绝非贬义词,它可以给我带来方便,是一种便捷的写法,编译器会帮我们做转换:而且可以提高开发编码的效率,在性能上也不会带来损失.这让java开发人员羡慕不已,呵呵. 1. ...
- mysql 分库分表的方法
分表后怎么做全文搜索 1.merge方式分表(不好) 2. 使用 sql union 3 使用Sphinx全文检索引擎 一,先说一下为什么要分表 当一张的数据达到几百万时,你查询一次所花的时间会变多, ...