1、链表的介绍
链表是一种线性存储结构,拥有n(n>=0)个同类型的元素组成,链表中的元素通常包含数据和一个或两个指向其他节点的引用。
2、java实现单向链表(可以存储任意类型)
首先写一个通用的接口:
interface Link<T>{
public void addFirst(T item);
public void addLast(T item);
public T getFisrt();
public T getLast();
public T get(int index);
public void set(int index,T item);
public void insert(int index,T item);
public T del(int index);
public T removeFirst();
public T removeLast();
public int size();
public boolean isNull();
public void printLink();
public boolean chechIndex(int index);
public boolean checkPosition(int index);
}
单链表实现类:
class SLink<T> implements Link<T>{
private int size = 0;
private Node<T> first;
private Node<T> last;
private static class Node<T>{
T item;
Node<T> next;
Node(T item,Node<T> nextNode){
this.item = item;
this.next = nextNode;
}
}
@Override
public void addFirst(T item) {
// TODO Auto-generated method stub
Node<T> newNode = new Node<T>(item, first);
if(first == null){
first = newNode;
last = newNode;
}else {
first = newNode;
}
size++;
}
@Override
public void addLast(T item) {
// TODO Auto-generated method stub
Node<T> newNode = new Node<T>(item, null);
if(last == null){
first = newNode;
last = newNode;
}else {
last.next = newNode;
last = newNode;
}
size++;
}
@Override
public T getFisrt() {
// TODO Auto-generated method stub
if(first == null)
throw new NoSuchElementException();
return first.item;
}
@Override
public T getLast() {
// TODO Auto-generated method stub
if(last == null)
throw new NoSuchElementException();
return last.item;
}
@Override
public T get(int index) {
// TODO Auto-generated method stub
if(!chechIndex(index))
throw new IndexOutOfBoundsException("index超出限度");
T item = null;
Node<T> node = first;
for (int i = 0; i <= index; i++) {
if(i == index)
item = node.item;
node = node.next;
}
return item;
}
@Override
public void set(int index, T item) {
// TODO Auto-generated method stub
if(!chechIndex(index))
throw new IndexOutOfBoundsException("index超出限度");
Node<T> node = first;
for (int i = 0; i <= index; i++) {
if(i == index)
node.item = item;
node = node.next;
}
}
@Override
public void insert(int index, T item) {
// TODO Auto-generated method stub
if(!checkPosition(index))
throw new IndexOutOfBoundsException("index超出限度");
Node<T> node = first;
Node<T> node1 = null;
Node<T> newNode = new Node<T>(item, null);
if (index == size) {
addLast(item);
}
else if (index == 0) {
addFirst(item);
}
else {
for (int i = 0; i <= index; i++) {
if(i == index - 1){
//保存原来索引位置的值
node1 = node.next;
//将新节点插入到原位置
node.next = newNode;
}
else if(i == index){
//新节点连上原来位置的节点
node.next = node1;
}
node = node.next;
}
size++;
}
}
@Override
public T removeFirst() {
// TODO Auto-generated method stub
T item = null;
if(first == null)
throw new IndexOutOfBoundsException("index超出限度");
item = first.item;
first = first.next;
if(first == null)
last = null;
size--;
return item;
}
@Override
public T removeLast() {
// TODO Auto-generated method stub
T item = null;
Node<T> node = first;
if(last == null)
throw new IndexOutOfBoundsException("index超出限度");
item = last.item;
if(size == 1)
removeFirst();
else if(size>1){
for (int i = 0; i < size-1; i++) {
if(i == size-2){
node.next = null;
last = node;
}
node = node.next;
}
size--;
}
return item;
}
@Override
public T del(int index) {
if(!chechIndex(index))
throw new IndexOutOfBoundsException("index超出限度");
T item = null;
Node<T> node = first;
Node<T> node1 = null;
if(index == 0){
item = removeFirst();
}
else if (index == size - 1) {
item = removeLast();
}
else {
for (int i = 0; i <= index + 1; i++) {
if(i == index - 1){
//保存索引位置前一个点
node1 = node;
}
else if(i == index){
item = node.item;
node1.next = node.next;
}
node = node.next;
}
size--;
}
return item;
}
@Override
public int size() {
// TODO Auto-generated method stub
return size;
}
@Override
public boolean isNull() {
// TODO Auto-generated method stub
return size == 0;
}
@Override
public void printLink() {
// TODO Auto-generated method stub
Node<T> node = first;
for (int i = 0; i < size; i++) {
System.out.print(node.item);
node = node.next;
}
System.out.println();
}
@Override
public boolean chechIndex(int index) {
// TODO Auto-generated method stub
return index<size&&index>=0;
}
@Override
public boolean checkPosition(int index) {
// TODO Auto-generated method stub
return index<=size&&index>=0;
}
}
操作示例:
SLink<Integer> sLink = new SLink<>();
sLink.addFirst(1);
sLink.addFirst(2);
sLink.addFirst(3);
sLink.addLast(4);
sLink.removeLast();
sLink.insert(0, 4);
sLink.removeLast();
sLink.removeLast();
sLink.del(1);
sLink.printLink();
System.out.println(sLink.size());
对于单链表来讲,这里用了新建了两个节点first和last指向链表头部和尾部,方便获取和删除头部和尾部的值,然后这里需要注意的是,每次添加删除都要考虑到size大小,first、last的指向是否需要改变,插入节点的时候一定要注意插入点和插入点两旁点的指向关系要修改,删除节点的时候也是一样。
3、java实现双向链表(可存储任意类型)
代码如下:
class Dlink<T> implements Link<T>{
private int size = 0;
private Node<T> first;
private Node<T> last;
private static class Node<T>{
T item;
Node<T> next;
Node<T> prev;
public Node(Node<T> prev,T item,Node<T> next) {
// TODO Auto-generated constructor stub
this.item = item;
this.prev = prev;
this.next = next;
}
}
@Override
public void addFirst(T item) {
Node<T> newnNode = new Node<>(null, item, first);
if (first == null) {
first = newnNode;
last = newnNode;
}else{
first.prev = newnNode;
first = newnNode;
}
size++;
}
@Override
public void addLast(T item) {
Node<T> newnNode = new Node<>(last, item, null);
if (last == null) {
first = newnNode;
last = newnNode;
}else{
last.next = newnNode;
last = newnNode;
}
size++;
}
@Override
public T getFisrt() {
chechIndex(0);
return first.item;
}
@Override
public T getLast() {
chechIndex(0);
return last.item;
}
@Override
public T get(int index) {
chechIndex(index);
if(index<(size>>1)){
Node<T> node = first;
for (int i = 0; i < index; i++) {
node = node.next;
}
return node.item;
}else {
Node<T> node = last;
for (int i = size-1; i > index; i--) {
node = node.prev;
}
return node.item;
}
}
@Override
public void set(int index, T item) {
chechIndex(index);
if(index<(size>>1)){
Node<T> node = first;
for (int i = 0; i < index; i++) {
node = node.next;
}
node.item = item;
}else {
Node<T> node = last;
for (int i = size-1; i > index; i--) {
node = node.prev;
}
node.item = item;
}
}
@Override
public void insert(int index, T item) {
checkPosition(index);
Node<T> newnNode = new Node<T>(null, item, null);
Node<T> node = first;
if (index == 0) {
addFirst(item);
}else if (index == size) {
addLast(item);
}
else {
for (int i = 0; i < index; i++) {
node = node.next;
}
//将新插入的点前后指向索引两边的点
newnNode.prev = node.prev;
newnNode.next = node;
//索引两边的点指向这个插入点
node.prev.next = newnNode;
node.prev = newnNode;
size++;
}
}
@Override
public T del(int index) {
chechIndex(index);
Node<T> node = first;
Node<T> cunNode = null;
T item = null;
if (index == 0) {
removeFirst();
}else if (index == size-1) {
removeLast();
}else {
for (int i = 0; i <= index; i++) {
if (i == index-1) {
cunNode = node;
}
if (i == index) {
item = node.item;
}
node = node.next;
}
cunNode.next = node;
node.prev = cunNode;
size--;
}
return item;
}
@Override
public T removeFirst() {
chechIndex(0);
T item = first.item;
first = first.next;
if (first == null) {
last = null;
}else {
first.prev = null;
}
size--;
return item;
}
@Override
public T removeLast() {
chechIndex(0);
T item = last.item;
last = last.prev;
if (last == null) {
first = null;
}else {
last.next = null;
}
size--;
return item;
}
@Override
public int size() {
return size;
}
@Override
public boolean isNull() {
return size == 0;
}
@Override
public void printLink() {
chechIndex(0);
Node<T> node = first;
while(node != null){
System.out.print(node.item);
node = node.next;
}
System.out.println();
}
@Override
public boolean chechIndex(int index) {
return index<size&&index>=0;
}
@Override
public boolean checkPosition(int index) {
// TODO Auto-generated method stub
return index<=size&&index>=0;
}
}
操作示例:
Dlink<Integer> dlink = new Dlink<>();
dlink.addFirst(1);
dlink.addFirst(2);
dlink.addFirst(3);
dlink.addFirst(4);
dlink.insert(1, 1);
dlink.addLast(5);
dlink.removeFirst();
dlink.removeLast();
dlink.removeLast();
dlink.removeLast();
dlink.del(1);
dlink.del(0);
dlink.insert(0, 1);
dlink.insert(1, 1);
dlink.insert(1, 2);
dlink.del(1);
dlink.set(1, 8);
dlink.printLink();
System.out.println(dlink.get(0));
System.out.println(dlink.size());
对于双链表,这里也新建了两个节点first和last指向头部和尾部,不仅可以方便的获取和删掉尾部的值,因为是双向的查找节点的时候可以根据索引的值从前面查找或者从后面开始查找,添加和删除节点的时候也要注意索引点两边节点的指向关系要修正。
4、对比
双向列表查找的时候更有效率,不仅可以从前往后找还可以从后往前找。