您的位置:首页 > 理论基础 > 数据结构算法

数据结构与算法之单向链表 <一>

2017-03-01 17:12 447 查看
数据结构与算法是优秀的程序员都应该熟悉的

今天我们就来学习最简单也是最常用的算法之一 单向链表

首先我们应该明白链表优缺点是啥

链表的优点

能在常数时间内拓展 这比数组要好得多,创建数组时必须分配一定大小的内存,如果需要扩充数组,那么 必须创建一个大的新数组然后将原数组中的元素复制过去耗费大量时间

链表缺点链表有许多不足 主要缺点在于访问单个元素时间耗费过大,数组访问任意元素的时间开销是O(1) 而链表在最差的情况下是O(n)

还有链表的额外指针引用浪费内存

既然优缺点我们都明白了,任何东西都不可能是十全十美,现在我们开始实现链表算法

首先创建节点对象

//节点对象 对象应该包含储蓄的数据和指向下一个节点对象
//利用泛型 将储存的数据类型交给使用者来选择,大大提升灵活性
public class Node<E> {
// 储存的数据
private E data;
// 下一个节点
private Node<E> next;

public E getData() {
return data;
}

public void setData(E data) {
this.data = data;
}

public Node<E> getNext() {
return next;
}

public void setNext(Node<E> next) {
this.next = next;
}
}


接下来创建链表对象并且实现一些功能

public class OneWayLinkedList<E> {

private Node<E> headNode;
private Node<E> endNode;

// 在链表最后增加链表节点
public void add(E obj) {
Node<E> node = new Node<>();
node.setData(obj);
// 如果链表为空 则首尾节点都指向第一个节点
if (headNode == null) {
headNode = node;
endNode = node;
} else {
// 不为空 将尾节点指向新增节点
endNode.setNext(node);
// 尾节点后移
endNode = node;
}
}

// 在指定中间位置增加节点
public void add(int index, E element) {
Node<E> node = new Node<>();
node.setData(element);

if (headNode == null) {
throw new NullPointerException("空链表");
}
// 判断位置是否超出界限
else if ((index < 0) || (index > this.size())) {
throw new ArrayIndexOutOfBoundsException("超出范围");
} else {
// 首节点插入
if (index == 0) {
node.setNext(headNode);
headNode = node;
}
// 尾节点插入
else if (index == this.size()) {
endNode.setNext(node);
endNode = node;
}
// 中间插入
else {
Node<E> hnode = headNode;
// 将首节点移动到插入节点的前一个节点
for (int i = 1; i <= index - 1; i++) {
hnode = hnode.getNext();
}
node.setNext(hnode.getNext());
hnode.setNext(node);
}
}
}

// 移除此列表中指定位置上的元素
public void remove(int index) {

if (headNode == null) {
throw new NullPointerException("空链表");
} else if ((index < 0) || (index >= this.size())) {
throw new ArrayIndexOutOfBoundsException("超出范围");
} else {
// 保护头结点
Node<E> hnode = headNode;
// 删除首节点
if (index == 0) {
headNode = headNode.getNext();
//System.out.println(index + "号:" + hnode.getData().toString() + "移除成功");
}
// 删除尾节点
else if (index == (this.size() - 1)) {
while (hnode.getNext() != null) {
hnode=hnode.getNext();
}
hnode.setNext(null);
//System.out.println(index + "号:" + endNode.getData() + " 移除成功");
endNode = hnode;
}
// 删除中间节点
else {
for (int i = 1; i < index; i++) {
hnode = hnode.getNext();
}
//E data = hnode.getNext().getData();
hnode.setNext(hnode.getNext().getNext());
//System.out.println(index + "号:" + data.toString() + " 移除成功");
}
}
}

// 返回此列表中指定位置上的元素。
public E get(int index) {
if (headNode == null) {
throw new NullPointerException("空链表");
} else {
// 遍历不到尾节点
for (Node<E> node = headNode; node.getNext() != null; node = node.getNext()) {
if (index == 0) {
return node.getData();
}
index--;
}
// 尾节点单独检测 为什么是0因为index多运行了一次
if (index == 0) {
return endNode.getData();
} else
throw new ArrayIndexOutOfBoundsException("超出范围");
}

}

// 返回此列表的元素数。
public int size() {
if (headNode == null) {
return 0;
} else {
Node<E> node = headNode;
int count = 0;
while (node.getNext() != null) {
node = node.getNext();
count++;
}
return count + 1;
}
}

// 用指定的元素替代此列表中指定位置上的元素。
public E set(int index, E element) {
//删除指定位置的元素
this.remove(index);
//插入指定位置元素
this.add(index, element);
return element;
}

//  @Test
//  public void test() {
//
//      OneWayLinkedList<Integer> oneWayLinkedList = new OneWayLinkedList<>();
//      for (int i = 0; i < 20; i++)
//          oneWayLinkedList.add(i);
//      System.out.println(oneWayLinkedList.get(19));
//      oneWayLinkedList.set(19, 15);
//      System.out.println(oneWayLinkedList.get(19));
//  }

public Node<E> getHeadNode() {
return headNode;
}

public void setHeadNode(Node<E> headNode) {
this.headNode = headNode;
}

public Node<E> getEndNode() {
return endNode;
}

public void setEndNode(Node<E> endNode) {
this.endNode = endNode;
}

}


至此单向链表基础功能已经实现了。希望对大家有所帮助。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据结构 链表 算法