本文表述了线性表及其基本操作的代码【Java实现】

参考书籍 :《数据结构 ——Java语言描述》/刘小晶 ,杜选主编

线性表需要的基本功能有:动态地增长或收缩;对线性表的任何数据元素进行访问和查找;在线性表中的任何位置进行数据元素的插入和删除操作;求线性表中指定数据元素的前驱和后继等等。

首先描述线性表的抽象类型,我们使用Java接口interface:

Ilist.java:

package liner_list;

public interface IList
{
public void clear();
public boolean isEmpty();
public int length();
public Object get(int i) throws Exception;
public void insertAt(int i,Object x) throws Exception;
public void remove(int i) throws Exception;
public int indexOf(Object x);
public void display();
}

其次描述顺序表,其特点有:在线性表中的逻辑上相邻的数据元素,在物理存储位置上也是相邻的;存储密度高,但需要预先分配”足够应用“的存储空间,这可能将会造成存储空间的浪费;便于随机存储;不便于插入和删除,因为在顺序表中进行插入和删除操作会引起大量数据元素的移位。我们用SqList类描述顺序表:

SqList.java:

package liner_list;

// 规定方法中的参数i都为顺序表元素的索引(下标)
public class SqList implements IList
{
public Object[] listItem; // 顺序表存储空间
public int curLen; // 线性表的当前长度 public SqList(int maxSize)
{
listItem = new Object[maxSize]; // 为顺序表分配maxSize个存储单元
curLen = 0; // 置当前长度为0
} public void clear()
{
curLen = 0; // 置当前长度为0,即规定为清空顺序表,但是内存中还有数据存在
} public boolean isEmpty()
{
return curLen == 0;
} public int length()
{
return curLen; // 返回当前长度
} public Object get(int i) throws Exception // 得到下标为i的元素,同时判断异常
{
if (i >= curLen || i < 0) // 索引越界,0<=index<=curLen
{
throw new Exception("Argument 'i' is out of range!");
}
return listItem[i];
} public void insertAt(int i, Object x) throws Exception // 在下表为i的位置插入元素x,同时判断异常
{
if (curLen == listItem.length) // 判断表满
{
throw new Exception("SqList is full!");
}
if (i > curLen || i < 0) // 索引越界,可以在curLen的位置进行插入
{
throw new Exception("Argument 'i' is out of range!");
}
for (int j = curLen; j > i; j--) // j从curLen的位置开始,即当前表最后一个元素的后一个位置,从而使得i位置及以后位置上的元素向后移一位
{
listItem[j] = listItem[j - 1];
}
listItem[i] = x; // 将x元素插入i位置
curLen++; // 插入后表长加一
} public void remove(int i) throws Exception
{
if (i >= curLen || i < 0) // i小于0或者大于等于表长时抛出异常
{
throw new Exception("Argument 'i' is out of range!");
}
for (int j = i; j < curLen - 1; j++) // 从i位置开始向后,不能从最后开始,否则最后一个元素将覆盖所有元素,若想从后向前,必须将被覆盖的元素保留给下一个元素
{
listItem[j] = listItem[j + 1];
}
curLen--; // 删除完后curLen减一
} public int indexOf(Object x) // 规定返回-1表示未找到元素x
{
for (int i = 0; i < curLen; i++)
{
if (listItem[i].equals(x))
{
return i;
}
}
return -1;
// 书本代码,效果相同
// int j = 0;
// while (j < curLen && !listItem[j].equals(x))
// {
// j++;
// }
// if (j < curLen)
// {
// return j;
// } else
// {
// return -1;
// }
} public void display() // 输出顺序表中全部元素
{
System.out.println("****** SqList ******");
for (int i = 0; i < curLen; i++)
{
System.out.print(listItem[i] + " ");
}
System.out.println();
System.out.println("********************");
}
}

接着测试我们的顺序表,使用SqListTest类来做测试:

SqListTest.java:

package liner_list;

import java.util.Scanner;

public class SqListTest
{
public static void main(String[] args) throws Exception
{
SqList sq1 = new SqList(10);
sq1.insertAt(0, "a0");
sq1.insertAt(1, "a1");
sq1.insertAt(2, "a2");
sq1.insertAt(3, "a3");
sq1.insertAt(4, "a4");
sq1.insertAt(5, "a5");
int index = sq1.indexOf("a2");
if (index != -1)
{
System.out.println("a2's index is " + index + "!");
} else
{
System.out.println("a5 is not in this SqList!");
}
sq1.display();
sq1.remove(2);
System.out.println("After remove:");
sq1.display();
SqList sq2 = new SqList(10);
Scanner sc = new Scanner(System.in);
System.out.println("Please input element:");
for (int i = 0; i < 8; i++)
{
sq2.insertAt(i, sc.next());
}
sc.close();
sq2.display();
}
}

运行我们的测试类,得到以下测试结果:

然后描述单链表,注意:我们推荐使用带头结点的单链表。这里总结以下关于头指针和头结点的问题:首先要清楚,head就是头指针,毋庸置疑;如果有头结点的话,head也头结点,这里头指针就是头结点,一般说成头指针指向头结点,而head.next是下标为0的元素,规定 head是下标为-1的元素;如果没有头结点的话,head本是就是下标为0的元素,这里没有头结点,但是head还是头指针。下面我们来描述结点类,它由两部分组成,data数据域和next指针域:

Node.java:

package liner_list;

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;
}
}

我们用LinkList类来描述带头结点的单链表:

LinkList.java:

package liner_list;

import java.util.Scanner;

//关于头结点与头指针的问题
//首先要清楚,head就是头指针,毋庸置疑
//如果有头结点的话,head也头结点,这里头指针就是头结点,一般说成头指针指向头结点,而head.next是下标为0的元素,规定 head是下标为-1的元素
//如果没有头结点的话,head本是就是下标为0的元素,这里没有头结点,但是head还是头指针
//建议写带头结点的单链表,此类就是一个典例
public class LinkList implements IList
{
public Node head; public LinkList() // 无参构造方法,只构建头指针
{
head = new Node();
} public LinkList(int len, boolean Order) throws Exception // 带有两个参数的构造方法,分别为表长和插入的方式,规定true表示尾插法,flase表示头插法
{
this();
if (Order)
{
createAtEnd(len);
} else
{
createAtHead(len);
}
} public void createAtHead(int n) throws Exception // 头插法
{
Scanner sc = new Scanner(System.in);
System.out.println("Please input element:");
for (int i = 0; i < n; i++)
{
insertAt(0, sc.next());
}
// sc.close(); // 不要关闭输入流
// display();
} public void createAtEnd(int n) throws Exception // 尾插法
{
Scanner sc = new Scanner(System.in);
System.out.println("Please input element:");
for (int i = 0; i < n; i++)
{
insertAt(length(), sc.next());
}
// sc.close(); // 不要关闭输入流
// display();
} @Override
public void clear() // 置空链表
{
head.data = null;
head.next = null;
} @Override
public boolean isEmpty() // 链表判空
{
return head.next == null;
} @Override
public int length() // 返回链表长度
{
Node p = head.next; // p指向首结点
int length = 0;
while (p != null)
{
p = p.next;
length++;
}
return length;
} @Override
public Object get(int i) throws Exception
{
Node p = head.next;
int j = 0;
while (p != null && j < i) // 从首结点开始向后查找,直到p指向第i个结点或者p为空
{
p = p.next; // 指针后移
j++; // 计数加1
}
if (i < 0 || p == null) // i小于0或者大于表长减1时抛出异常
{
throw new Exception("Argument 'i' is out of range!");
}
return p.data;
} @Override
public int indexOf(Object x) // 规定-1表示不在LinkList当中
{
Node p = head.next;
int index = 0;
while (p != null && !p.data.equals(x))
{
p = p.next;
index++;
}
if (p != null)
{
return index;
} else
{
return -1;
}
} @Override
public void insertAt(int i, Object x) throws Exception
{
Node p = head; // 插入时从头结点开始,因为可以插入在下标0的位置,也可以插入在下标为表长位置
int j = -1;
while (p != null && j < i - 1) // 找出下标为i-1的结点,即i结点的前驱
{
p = p.next;
j++;
}
if (i < 0 || p == null) // i小于0或者i大于表长时抛出异常
{
throw new Exception("Argument 'i' is out of range!");
}
Node s = new Node(x);
s.next = p.next;
p.next = s;
} @Override
public void remove(int i) throws Exception
{
Node p = head;
int j = -1;
while (p != null && j < i - 1) // 找到下标为i-1的结点,即i结点的前驱
{
p = p.next;
j++;
}
if (i < 0 || p.next == null) // 抛出条件为i小于0或者i大于表长-1,所以此处为p.next==null
{
throw new Exception("Argument 'i' is out of range!");
}
p.next = p.next.next;
} @Override
public void display()
{
Node p = head.next;
System.out.println("****** LinkList ******");
while (p != null)
{
System.out.print(p.data.toString() + " ");
p = p.next;
}
System.out.println();
System.out.println("*********************");
} }

最后测试我们的单链表,使用LinkListTest类来做测试:

LinkListTest.java

package liner_list;

public class LinkListTest
{
public static void main(String[] args) throws Exception
{
LinkList linkList = new LinkList(10, true);
linkList.remove(0);
linkList.remove(1);
linkList.remove(linkList.length() - 1);
System.out.println("After remove:");
linkList.display();
linkList.insertAt(linkList.length(), "a9");
System.out.println("After insert:");
linkList.display();
int index = linkList.indexOf("a2");
if (index != -1)
{
System.out.println("a2's index is " + index + "!");
} else
{
System.out.println("a2 is not in this LinkList!");
}
}
}

运行我们的测试类,得到以下结果:

以上便是线性表中顺序表和单链表最基础的代码描述,算法思想本文中没有写到,大家可以去看看前面说的那本参考书籍。此系列后面会陆续介绍更多有关数据结构的内容,也会更新一些关于数据结构的算法题目例子,谢谢大家支持!

【线性表基础】顺序表和单链表的插入、删除等基本操作【Java版】的更多相关文章

  1. 单链表的插入删除操作(c++实现)

    下列代码实现的是单链表的按序插入.链表元素的删除.链表的输出 // mylink.h 代码 #ifndef MYLINK_H #define MYLINK_H #include<iostream ...

  2. [C++]数据结构:线性表之顺序表

    1 顺序表 ADT + Status InitList(SeqList &L) 初始化顺序表 + void printList(SeqList L) 遍历顺序表 + int ListLengt ...

  3. C#线性表之顺序表

    线性表是最简单.最基本.最常用的数据结构.线性表是线性结构的抽象(Abstract), 线性结构的特点是结构中的数据元素之间存在一对一的线性关系. 这种一对一的关系指的是数据元素之间的位置关系,即: ...

  4. c/c++ 线性表之顺序表

    线性表之顺序表 存储在连续的内存空间,和数组一样. 下面的代码,最开始定义了一个能存8个元素的顺序表,当超过8个元素的时候,会再追加开辟空间(函数:reInit). 实现了以下功能: 函数 功能描述 ...

  5. 线性表之顺序表C++实现

    线性表之顺序表 一.头文件:SeqList.h //顺序线性表的头文件 #include<iostream> ; //定义顺序表SeqList的模板类 template<class ...

  6. [数据结构 - 第3章] 线性表之顺序表(C++实现)

    一.类定义 顺序表类的定义如下: #ifndef SEQLIST_H #define SEQLIST_H typedef int ElemType; /* "ElemType类型根据实际情况 ...

  7. 数据结构Java实现02----线性表与顺序表

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  8. 数据结构Java实现01----线性表与顺序表

    一.线性结构: 如果一个数据元素序列满足: (1)除第一个和最后一个数据元素外,每个数据元素只有一个前驱数据元素和一个后继数据元素: (2)第一个数据元素没有前驱数据元素: (3)最后一个数据元素没有 ...

  9. 面试之路(10)-BAT面试之java实现单链表的插入和删除

    链表的结构: 链表在空间是不连续的,包括: 数据域(用于存储数据) 指针域(用于存储下一个node的指针) 单项链表的代码实现: 节点类 构造函数 数据域的get,set方法 指针域的get,set方 ...

随机推荐

  1. Codeforces 735D Taxes(简单数论)

    题目链接 http://codeforces.com/problemset/problem/735/D 题意:一个人的收入为n他要交的税是n的最大除数,他为了少缴税将n分成k个数n1,n2,n2... ...

  2. [系列] go-gin-api 路由中间件 - 捕获异常(四)

    概述 首先同步下项目概况: 上篇文章分享了,路由中间件 - 日志记录,这篇文章咱们分享:路由中间件 - 捕获异常.当系统发生异常时,提示 "系统异常,请联系管理员!",同时并发送 ...

  3. Word 远程调用失败:异常来自 HRESULT:0x800706BE

    之前服务器上一直运行正常的,这几天突然报错 “远程过程调用失败. (异常来自 HRESULT:0x800706BE) ” 解决方案:组件服务—我的电脑—属性—COM安全—编辑默认值  添加各种用户权限 ...

  4. Python学习之旅:用Python制作一个打字训练小工具

    一.写在前面 说道程序员,你会想到什么呢?有人认为程序员象征着高薪,有人认为程序员都是死肥宅,还有人想到的则是996和 ICU. 别人眼中的程序员:飞快的敲击键盘.酷炫的切换屏幕.各种看不懂的字符代码 ...

  5. asp.net core 使用 NLog日志

    NLog是一个配置灵活的日志记录类库,拥有输出日志到文件.存储入库.发送到udp地址的高级功能 1 添加 nlog nuget包 Nlog和NLog.Web.AspNetCore 安装完成后   2 ...

  6. Docker的优缺点

    Docker解决的问题 由于不同的机器有不同的操作系统,以及不同的库和组件,将一个应用程序部署到多台机器上需要进行大量的环境配置操作.(例如经常出现的类似"在我的机器上就没问题"这 ...

  7. 作为Java开发人员不会饿死的5个理由

    尽管已有20多年的历史,Java仍然是最广泛使用的编程语言之一.只需看看统计数据:根据2018年Stack Overflow开发人员调查,Java是世界上第三大最受欢迎的技术. TIOBE指数,这是一 ...

  8. setuptools的安装

    Python 2.x:    sudo apt-get install python-setuptools           (python2.x版本执行此命令) Python 3.x:    su ...

  9. DirectX12 3D 游戏开发与实战第三章内容

    变换 学习目标 理解如何使用矩阵表示线性变换和仿射变换 学习对几何体进行缩放.旋转和平移的坐标变换 根据矩阵之间的乘法运算性质,将多个变换矩阵合并为一个单独的净变换矩阵 找寻不同坐标系之间的坐标转换方 ...

  10. Jenkins把GitHub项目做成Docker镜像

    本文是<Jenkins流水线(pipeline)实战>系列的第三篇,前面已对Jenkins流水线有了基本认识,也试过从GitHub下载pipeline脚本并执行,今天的实战是编写一段pip ...