Java数据结构之链表
概述
数组和链表都是最基础的线性数据结构,可以用来实现栈,队列等非线性,有特定应用场景的数据结构,我们发现数组作为数据存储结构有很很多缺陷,在无序数组中搜索效率低,在有序数组中插入效率又很低,无论哪种情况删除操作效率都很低;而且数组一旦创建,大小不可更改。
本文我们介绍一种新的数据储存结构,链表,除非是要频繁通过下标访问数据,否则在很多场合都可以用链表替换数组;
1链表组成结构
链表通常由一连串节点组成,每个节点包含该节点的数据和指向上一节点或者下一节点的引用(链接)
2 单向链表
单向链表是最简单的链表,单链表节点包含两部分内容,一是保存某些数据信息的对象,另一个是存储下一个节点的地址,最后一个节点存储的地址是指向空值;
单向链表只可向一个方向遍历,一般查找一个节点的时候需要从第一个节点开始每次访问下一个节点,一直访问到需要的位置。而插入一个节点,对于单向链表,我们只提供在链表头插入,只需要将当前插入的节点设置为头节点,next指向原头节点即可。删除一个节点,我们将该节点的上一个节点的next指向该节点的下一个节点。
在链表头增加新节点 :
删除节点:
代码演示:
package datastrunture.link; public class SingleLinkList { private int size; private Node head; public SingleLinkList() { this.size = 0; this.head = null; } /** * 链表每个节点类 */ private class Node{ private Object data; private Node next; public Node(Object data){ this.data=data; } } //在链表头添加节点 public void addHead(Object data){ Node newHead = new Node(data); if(size==0){ head = newHead; }else{ newHead.next = head; head = newHead; } size++; } //删除链表头的元素 public Object deleteHead() { if (size > 0) { Object data = head.data; head = head.next; size--; return data; } return null; } //查找指定元素,找到返回节点Node public Node find(Object obj){ Node current = head; int tempSize = size; while(tempSize>0){ if(obj.equals(current.data)){ return current; }else{ current = current.next; } tempSize--; } return null; } //删除指定元素 public boolean delete(Object value){ if(size==0){ return false; } Node current = head; Node pre = head; while (current.data!=value){ if(current.next==null){ return false; }else { pre = current; current = current.next; } } if(current == head){ head = current.next; size--; }else { pre.next = current.next; size--; } return true; } //判断是否为空 public boolean isEmpty(){ return (size==0); } //遍历链表 public void display(){ if(size>0){ Node node = head; int tempSize = size; if(tempSize ==1){ System.out.print( "["+node.data+"]"); } while(tempSize>0){ if(node.equals(head)){ System.out.print("["+node.data+"->"); }else if(node.next == null){ System.out.print(node.data+"]"); }else{ System.out.print(node.data+"->"); } node = node.next; tempSize--; } System.out.println(); }else{ System.out.println("[]"); } } }
3 双端链表:
对于单项链表,我们如果想在尾部添加一个节点,那么必须从头部一直遍历到尾部,找到尾节点,然后在尾节点后面插入一个节点。这样操作很麻烦,如果我们在设计链表的时候多个对尾节点的引用,那么会简单很多。
代码演示:
package datastrunture.link; public class DoublePointLinkedList { private Node head;//头节点 private Node tail;//尾节点 private int size;//节点的个数 private class Node{ private Object data; private Node next; public Node(Object data){ this.data = data; } } public DoublePointLinkedList(){ size = 0; head = null; tail = null; } //链表头新增节点 public void addHead(Object data){ Node node = new Node(data); if(size == 0){//如果链表为空,那么头节点和尾节点都是该新增节点 head = node; tail = node; }else{ node.next = head; head = node; } size++; } //链表尾新增节点 public void addTail(Object data){ Node node = new Node(data); if(size == 0){//如果链表为空,那么头节点和尾节点都是该新增节点 head = node; tail = node; }else{ tail.next = node; tail = node; } size++; } //删除头部节点,成功返回true,失败返回false public boolean deleteHead(){ if(size == 0){//当前链表节点数为0 return false; } if(head.next == null){//当前链表节点数为1 head = null; tail = null; }else{ head = head.next; } size--; return true; } //判断是否为空 public boolean isEmpty(){ return (size ==0); } //获得链表的节点个数 public int getSize(){ return size; } //显示节点信息 public void display(){ if(size >0){ Node node = head; int tempSize = size; if(tempSize == 1){//当前链表只有一个节点 System.out.println("["+node.data+"]"); return; } while(tempSize>0){ if(node.equals(head)){ System.out.print("["+node.data+"->"); }else if(node.next == null){ System.out.print(node.data+"]"); }else{ System.out.print(node.data+"->"); } node = node.next; tempSize--; } System.out.println(); }else{//如果链表一个节点都没有,直接打印[] System.out.println("[]"); } } }
4 双向链表
package datastrunture.link; public class DoubleLinkedList { private Node head;//表示链表头 private Node tail;//表示链表尾 private int size;//表示链表的节点个数 private class Node{ private Object data; private Node next; private Node prev; public Node(Object data){ this.data = data; } } public DoubleLinkedList(){ size = 0; head = null; tail = null; } //在链表头增加节点 public void addHead(Object value){ Node newNode = new Node(value); if(size == 0){ head = newNode; tail = newNode; }else{ head.prev = newNode; newNode.next = head; head = newNode; } size++; } //在链表尾增加节点 public void addTail(Object value){ Node newNode = new Node(value); if(size == 0){ head = newNode; tail = newNode; }else{ newNode.prev = tail; tail.next = newNode; tail = newNode; } size++; } //删除链表头 public Node deleteHead(){ Node temp = head; if(size != 0){ head = head.next; head.prev = null; size--; } return temp; } //删除链表尾 public Node deleteTail(){ Node temp = tail; if(size != 0){ tail = tail.prev; tail.next = null; size--; } return temp; } //获得链表的节点个数 public int getSize(){ return size; } //判断链表是否为空 public boolean isEmpty(){ return (size == 0); } //显示节点信息 public void display(){ if(size >0){ Node node = head; int tempSize = size; if(tempSize == 1){//当前链表只有一个节点 System.out.println("["+node.data+"]"); return; } while(tempSize>0){ if(node.equals(head)){ System.out.print("["+node.data+"->"); }else if(node.next == null){ System.out.print(node.data+"]"); }else{ System.out.print(node.data+"->"); } node = node.next; tempSize--; } System.out.println(); }else{//如果链表一个节点都没有,直接打印[] System.out.println("[]"); } } }