前两篇内容为栈和队列的顺序结构的实现,栈和队列都是特殊的线性表,线性表除了有顺序结构以外,还有线性结构。

一.线性表的链形结构--链表

使用顺序存储结构好处为实现方式使用数组方式,顺序是固定的。所以查询某个位置的元素特别容易,时间复杂度为O(1),但是当增加或者删除时,会需要将操作元素后面的元素整体向左或者向右平移。时间复杂度为O(n)。所以当线性表查询操作多于增删操作,优先使用顺序存储结构的线性表;当线性表增删操作多于查询操作,则优先使用链式存储结构的线性表。

线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的。这就意味着,这些数据元素可以存在内存未被占用的任意位置。因为链表可以不连续的存储,所以每个元素需要记录一下他的后继的地址,从而实现每个不连续的元素之间实现关联。我们把元素内容信息和节点信息封装在一起,叫做结点。即每个结点拥有当前元素的信息以及此元素的后继结点的信息。

结点的代码描述可以为下方模型:这样可以通过某个结点获取其元素内容以及前一个和后一个结点。

 private class Node {
Object item; // 当前节点所包含的值
Node next; //下一个节点
Node prev; //上一个节点
Node(Node prev, Object element, Node next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}

 二.链表功能的实现

链表作为线性表应该包含一些基础的功能,包括添加,修改,删除等。下方代码实现了以下的功能:

Integer size():返回链表的长度;

addFirst(Object obj):在链表第一个位置添加元素;

add(Object obj):在链表尾部添加元素;

add(Object obj,Integer index):在指定位置添加元素,index从0开始;

Object removeFirst():移除列表中的第一个元素,并且返回它的值;

Object removeLast():移除列表中的最后一个元素,并且返回它的值;

Object remove(Integer index):移除指定位置的元素,index从0开始,并且返回它的值;

Boolean removeAll():移除所有的元素,成功返回true;

set(Integer index,Object obj):设置指定位置的value值;

Object[] toArray():将链表转换成数组,并返回数组;

toString():重写toString()方法,返回的数据结构为(obj1,obj2,...objn)

上述方法中,如果出现数组越界或者其他情况下,返回自定义的异常。代码如下:

 public without sharing class LinkedList {

     private Integer size = 0;

     private Node first;

     private Node last;

     public Integer size() {
return size;
} //在第一个位置添加元素
public void addFirst(Object obj) {
linkNode(obj,0);
} //在最后一个位置添加元素
public void add(Object obj) {
linkNode(obj,size);
} //在指定位置前添加元素
public void add(Object obj,Integer index) {
linkNode(obj,index);
} public Object removeFirst() {
return unLinkNode(0);
} public Object removeLast() {
return unLinkNode(size - 1);
} public Object remove(Integer index) {
return unLinkNode(index);
} public Boolean removeAll() {
return (Boolean)unLinkNode(null);
} public void set(Integer index,Object obj) {
checkPositionIndex(index,'edit');
Node operateNode = node(index,'edit');
operateNode.item = obj;
} public Object[] toArray() {
Object[] results = new Object[size];
Integer i = 0;
for(Node n = first;n != null;n = n.next) {
results[i++] = n.item;
}
return results;
} public Object get(Integer index) {
checkPositionIndex(index,'get');
Node result = node(index,'get');
return result.item;
} override public String toString() {
Object[] results = toArray();
return String.valueOf(results);
} private Object unLinkNode(Integer index) {
checkPositionIndex(index,'delete');
Node leftNode;
Node rightNode;
Node operateNode;
Object result;
if(index != null) {
if(index == 0) {//remove first
operateNode = first;
result = operateNode.item;
rightNode = operateNode.next;
first = rightNode;
//如果只有一个结点,则将last置空
if(rightNode == null) {
last = null;
} else {
rightNode.prev = null;
}
size--;
} else if(index == size - 1) {//remove last
operateNode = last;
result = operateNode.item;
leftNode = operateNode.prev;
last = leftNode;
if(leftNode == null) {
first = null;
} else {
leftNode.next = null;
}
size--;
} else {//remove index node
operateNode = node(index,'delete');
result = operateNode.item;
leftNode = operateNode.prev;
rightNode = operateNode.next;
if(leftNode != null) {
leftNode.next = rightNode;
}
if(rightNode != null) {
rightNode.prev = leftNode;
} else { } size--;
}
} else {//remove all
first = null;
last = null;
size = 0;
result = true;
}
return result;
} private void linkNode(Object e,Integer index) {
checkPositionIndex(index,'add');
Node newNode;
Node leftNode;
Node rightNode;
if(index == 0) {//add first
rightNode = first;
newNode = new Node(null,e,rightNode);
first = newNode;
if(rightNode == null) {
last = newNode;
} else {
rightNode.prev = newNode;
}
} else if(index == size) {//add last
leftNode = last;
newNode = new Node(leftNode,e,null);
last = newNode;
if(leftNode == null) {
first = newNode;
} else {
leftNode.next = newNode;
}
} else {//add node to specify index
//get the index node
rightNode = node(index,'add');
leftNode = rightNode.prev;
newNode = new Node(leftNode,e,rightNode);
rightNode.prev = newNode;
if(leftNode == null) {
first = newNode;
} else {
leftNode.next = newNode;
}
}
size++;
} //获取指定位置的结点元素,此部分可以进行优化。比如二分法或者其他处理从而减小循环的数量
private Node node(Integer index,String operateType) {
checkPositionIndex(index,operateType);
Node x = first;
for(Integer i = 1;i < size;i++) {
x = x.next;
if(index == i) {
break;
}
}
return x;
} //判断当前的index是否符合规范,比较其和size的关系以及是否大于0等校验
private void checkPositionIndex(Integer index,String operateType) { if(index < 0) {
throw new LinkedListException('index必须大于等于0');
} if('delete'.equalsIgnorecase(operateType)) {
if(size <= 0) {
throw new LinkedListException('链表长度必须大于0才可以删除');
}
} if(!'add'.equalsIgnorecase(operateType)) {
if(index >= size) {
throw new LinkedListException('index 越界!');
}
} } private class Node {
Object item; // 当前节点所包含的值
Node next; //下一个节点
Node prev; //上一个节点 Node(Node prev, Object element, Node next) {
this.item = element;
this.next = next;
this.prev = prev;
}
} public class LinkedListException extends Exception { }
}

三.测试结果

使用链表进行添加删除操作,并返回链表的值操作:

LinkedList ll = new LinkedList();
ll.add('aaa');
System.debug(LoggingLevel.INFO, '*** 1: ' + ll);
ll.addFirst('bbb');
System.debug(LoggingLevel.INFO, '*** 2: ' + ll);
ll.add('ccc',1);
System.debug(LoggingLevel.INFO, '*** 3: ' + ll);
ll.add('ddd');
System.debug(LoggingLevel.INFO, '*** 4: ' + ll);
System.debug(LoggingLevel.INFO, '*** ll.get(3): ' + ll.get(3));
ll.removeFirst();
System.debug(LoggingLevel.INFO, '*** 5: ' + ll);
ll.remove(2);
System.debug(LoggingLevel.INFO, '*** 6: ' + ll);
ll.set(1, 'set new obj');
System.debug(LoggingLevel.INFO, '*** 7: ' + ll); System.debug(LoggingLevel.INFO, '*** ll.get(0): ' + ll.get(0)); Object[] objs = ll.toArray();
for(Object obj : objs) {
System.debug(LoggingLevel.INFO, '*** obj: ' + obj);
}

结果显示:

总结:此篇简单的实现了链表的数据结构以及最基本的方法,里面没有对空指针进行太多的处理,应该有很多隐藏的bug,感兴趣的可以去完善,比如完善一下构造函数传链表或者数组情况,getFirst,getLast等等的方法。篇中有错误的地方欢迎指出,有问题欢迎交流。

salesforce零基础学习(七十八)线性表链形结构简单实现的更多相关文章

  1. salesforce 零基础学习(十八)WorkFlow介绍及用法

    说起workflow大家肯定都不陌生,这里简单介绍一下salesforce中什么情况下使用workflow. 当你分配许多任务,定期发送电子邮件,记录修改时,可以通过自动配置workflow来完成以上 ...

  2. salesforce 零基础学习(十九)Permission sets 讲解及设置

    Permission sets以及Profile是常见的设置访问权限的方式. Profile规则为'who see what'.通过Profile可以将一类的用户设置相同的访问权限.对于有着相同Pro ...

  3. salesforce零基础学习(九十八)Type浅谈

    在Salesforce的世界,凡事皆Metadata. 先通过一句经常使用的代码带入一下: Account accountItem = (Account)JSON.deserialize(accoun ...

  4. salesforce零基础学习(九十八)Salesforce Connect & External Object

    本篇参考: https://trailhead.salesforce.com/en/content/learn/modules/lightning_connect https://help.sales ...

  5. salesforce 零基础学习(十六)Validation Rules & Date/time

    上一篇介绍的内容为Formula,其中的Date/time部分未指出,此篇主要介绍Date/time部分以及Validation rules. 本篇参考PDF: Date/time:https://r ...

  6. salesforce零基础学习(八十)使用autoComplete 输入内容自动联想结果以及去重实现

    项目中,我们有时候会需要实现自动联想功能,比如我们想输入用户或者联系人名称,去联想出系统中有的相关的用户和联系人,当点击以后获取相关的邮箱或者其他信息等等.这种情况下可以使用jquery ui中的au ...

  7. salesforce零基础学习(八十九)使用 input type=file 以及RemoteAction方式上传附件

    在classic环境中,salesforce提供了<apex:inputFile>标签用来实现附件的上传以及内容获取.salesforce 零基础学习(二十四)解析csv格式内容中有类似的 ...

  8. salesforce 零基础学习(六十八)http callout test class写法

    此篇可以参考: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_restfu ...

  9. salesforce零基础学习(八十二)审批邮件获取最终审批人和审批意见

    项目中,审批操作无处不在.配置审批流时,我们有时候会用到queue,related user设置当前步骤的审批人,审批人可以一个或者多个.当审批人有多个时,邮件中获取当前记录的审批人和审批意见就不能随 ...

随机推荐

  1. 如何解决苹果Mac系统无法识别U盘

       1.在Mac机上打开“磁盘工具”,将U盘重新分区, 2.格式选“exFAT”.该格式分区Win及Mac系统中都可以读和写,特别是可以支持大于4GB的大文件.但是一些高清播放机可能不支持. 3.以 ...

  2. HTML基本结构与标签总结整理篇

    HTML基本结构与标签总结整理篇 前言:这是笔者的学习总结与整理,如果有错误或疑问的地方,欢迎指正与讨论!另:此文会不定时更新~ 1.了解HTML 学习前端技术,必然涉及三个方面:html(结构).c ...

  3. 1.0 配置 appium + java的环境

    1. 配置 appim的环境前面中写到.       2. 在eclipse中配置 java 环境, 具体步骤:       <1>:在 eclipse 中新建 一个java 项目.   ...

  4. epii.js简约而不简单的JS模板引擎

    epii.js是什么 epii.js是一个 模板引擎,可快速实现数据与ui绑定,快速实现事件绑定,与处理,不依赖任何第三方库,仅仅8k,在native+webapp开发 和 web开发,h5微网页上均 ...

  5. 浅谈web服务器的编写之http协议

    本书是介绍怎么编写一个Web服务器,而Web服务器是基于HTTP(HyperText Transfer Protocol)协议实现的,所以要实现一个Web服务器就必须了解HTTP协议,本章主要介绍HT ...

  6. linux UART

    #include <stdio.h> #include <string.h> #include <sys/types.h> #include <errno.h ...

  7. 第一章:火狐浏览器 : 环境配置: FireFox 版本38 + jdk 7 + selenium 2.53.6 + selenum-version 2.48.2

    配置一套完整的 selenium + Java + Firefox38  环境: 1. 火狐浏览器的版本 : 38 2. JDK 安装 1.7 版本的 3. 安装 Python 的版本是 2.7 4. ...

  8. LeetCode-Best Time to Buy and Sell Stock III[dp]

    Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...

  9. 【SignalR学习系列】3. SignalR实时高刷新率程序

    创建项目 创建一个空的 Web 项目,并在 Nuget 里面添加 SignalR,jQuery UI 包,添加以后项目里包含了 jQuery,jQuery.UI ,和 SignalR 的脚本. 创建基 ...

  10. 在Swift中实现 oc与swift的混编

    在Swift中想要引用OC头文件(import),可采用混编的方法,这里以sqlite为例,采用OC-Swift桥的方式实现添加头文件1引入sqlite数据库的库文件 打开工程配置文件,在build ...