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

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

使用顺序存储结构好处为实现方式使用数组方式,顺序是固定的。所以查询某个位置的元素特别容易,时间复杂度为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. jquery 封装

    (function($) { var plugName = "teamMingXi"; var teamMingXi = { open : function(type) { var ...

  2. Angular4 后台管理系统搭建(1) - 建立一个通用的Wijmo5 flexgrid分页器组件

    17年4月,开始学习angular2,到5月跟着升级到angular4.目前还在学习,搭建中.我的最终目的是用angular4框架搭建一个后台管理系统.这里使用了三个关键的外部库. 1.使用admin ...

  3. Kafka 源代码分析之LogSegment

    这里分析kafka LogSegment源代码 通过一步步分析LogManager,Log源代码之后就会发现,最终的log操作都在LogSegment上实现.LogSegment负责分片的读写恢复刷新 ...

  4. zookeeper client API实现(python kazoo 的实现)

    这里主要分析zookeeper client API的实现方式,以python kazoo的实现代码为蓝本进行逻辑分析. 一.代码框架及介绍 API分为同步模式和异步模式.同步模式是在异步模式的基础上 ...

  5. [翻译]成为顶尖程序员应当学什么?Python、C还是Ruby?

    原文地址(墙外):https://medium.com/life-tips/should-you-learn-python-c-or-ruby-to-be-a-top-coder-infographi ...

  6. java equals和==区别及string类的说明

    一.equals和==的区别 1.1.equals之string字符串的比较 1.1.1.源码如下图 if (this == anObject) {            return true;  ...

  7. 计算机浏览器存储技术cookie、sessionStorage、localStorage

    HTTP无状态协议是指协议对于事务处理没有记忆能力.会话跟踪协议的状态是指下一次传输可以"记住"这次传输信息的能力,无状态是指同一个会话(注意什么叫同一个会话)的连续两个请求互相不 ...

  8. python webserver, based on SimpleHTTPServer

    #-*- coding:utf-8 -*- #author: lichmama #email: nextgodhand@163.com #filename: httpd.py import io im ...

  9. 第2篇:用as3.0制作一个滚动条组件

    本实例演示了实现一个滚动条基本功能的制作方法,没有添加改变皮肤,修改滚动条视框大小等功能,有兴趣的朋友可根据自己要求自行添加.使用时只需要通过以下一行代码创建滚动条组件: var myScrollba ...

  10. js获取鼠标点击的对象,点击另一个按钮删除该对象

    作为js的一名新手,对于所谓的event的了解并不是太多,仅仅根据视频教学中的例子模仿着,写了诸如: function funcname(e) { e=window.event||event };的函 ...