1:链表(Linked list)
链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。
使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。
2:单向链表(single linked list)
单链表是链表中结构最简单的。一个单链表的节点(Node)分为两个部分,第一个部分(data)保存或者显示关于节点的信息,另一个部分存储下一个节点的地址。最后一个节点存储地址的部分指向空值。
单向链表只可向一个方向遍历,一般查找一个节点的时候需要从第一个节点开始每次访问下一个节点,一直访问到需要的位置。而插入一个节点,对于单向链表,我们只提供在链表头插入,只需要将当前插入的节点设置为头节点,next指向原头节点即可。删除一个节点,我们将该节点的上一个节点的next指向该节点的下一个节点。
在表头增加节点:
删除节点:
单向链表的具体实现
public class SingleLinkedList { 4 private int size;//链表节点的个数 5 private Node head;//头节点 6 7 public SingleLinkedList(){ 8 size = 0; 9 head = null; 10 } 11 12 //链表的每个节点类 13 private class Node{ 14 private Object data;//每个节点的数据 15 private Node next;//每个节点指向下一个节点的连接 16 17 public Node(Object data){ 18 this.data = data; 19 } 20 } 21 22 //在链表头添加元素 23 public Object addHead(Object obj){ 24 Node newHead = new Node(obj); 25 if(size == 0){ 26 head = newHead; 27 }else{ 28 newHead.next = head; 29 head = newHead; 30 } 31 size++; 32 return obj; 33 } 34 35 //在链表头删除元素 36 public Object deleteHead(){ 37 Object obj = head.data; 38 head = head.next; 39 size--; 40 return obj; 41 } 42 43 //查找指定元素,找到了返回节点Node,找不到返回null 44 public Node find(Object obj){ 45 Node current = head; 46 int tempSize = size; 47 while(tempSize > 0){ 48 if(obj.equals(current.data)){ 49 return current; 50 }else{ 51 current = current.next; 52 } 53 tempSize--; 54 } 55 return null; 56 } 57 58 //删除指定的元素,删除成功返回true 59 public boolean delete(Object value){ 60 if(size == 0){ 61 return false; 62 } 63 Node current = head; 64 Node previous = head; 65 while(current.data != value){ 66 if(current.next == null){ 67 return false; 68 }else{ 69 previous = current; 70 current = current.next; 71 } 72 } 73 //如果删除的节点是第一个节点 74 if(current == head){ 75 head = current.next; 76 size--; 77 }else{//删除的节点不是第一个节点 78 previous.next = current.next; 79 size--; 80 } 81 return true; 82 } 83 84 //判断链表是否为空 85 public boolean isEmpty(){ 86 return (size == 0); 87 } 88 89 //显示节点信息 90 public void display(){ 91 if(size >0){ 92 Node node = head; 93 int tempSize = size; 94 if(tempSize == 1){//当前链表只有一个节点 95 System.out.println("["+node.data+"]"); 96 return; 97 } 98 while(tempSize>0){ 99 if(node.equals(head)){ 100 System.out.print("["+node.data+"->"); 101 }else if(node.next == null){ 102 System.out.print(node.data+"]"); 103 }else{ 104 System.out.print(node.data+"->"); 105 } 106 node = node.next; 107 tempSize--; 108 } 109 System.out.println(); 110 }else{//如果链表一个节点都没有,直接打印[] 111 System.out.println("[]"); 112 } 113 114 } 115 116 }
测试:
@Test 2 public void testSingleLinkedList(){ 3 SingleLinkedList singleList = new SingleLinkedList(); 4 singleList.addHead("A"); 5 singleList.addHead("B"); 6 singleList.addHead("C"); 7 singleList.addHead("D"); 8 //打印当前链表信息 9 singleList.display(); 10 //删除C 11 singleList.delete("C"); 12 singleList.display(); 13 //查找B 14 System.out.println(singleList.find("B")); 15 }
打印结果:
用链表实现栈的功能:(主要是调用删除第一个,以及添加第一个的方法)
public class StackSingleLink { 4 private SingleLinkedList link; 5 6 public StackSingleLink(){ 7 link = new SingleLinkedList(); 8 } 9 10 //添加元素 11 public void push(Object obj){ 12 link.addHead(obj); 13 } 14 15 //移除栈顶元素 16 public Object pop(){ 17 Object obj = link.deleteHead(); 18 return obj; 19 } 20 21 //判断是否为空 22 public boolean isEmpty(){ 23 return link.isEmpty(); 24 } 25 26 //打印栈内元素信息 27 public void display(){ 28 link.display(); 29 } 30 31 }
2:双端链表:
对于单项链表,我们如果想在尾部添加一个节点,那么必须从头部一直遍历到尾部,找到尾节点,然后在尾节点后面插入一个节点。这样操作很麻烦,如果我们在设计链表的时候多个对尾节点的引用,那么会简单很多。
注意和后面将的双向链表的区别!!!
①、双端链表的具体实现
public class DoublePointLinkedList { 4 private Node head;//头节点 5 private Node tail;//尾节点 6 private int size;//节点的个数 7 8 private class Node{ 9 private Object data; 10 private Node next; 11 12 public Node(Object data){ 13 this.data = data; 14 } 15 } 16 17 public DoublePointLinkedList(){ 18 size = 0; 19 head = null; 20 tail = null; 21 } 22 23 //链表头新增节点 24 public void addHead(Object data){ 25 Node node = new Node(data); 26 if(size == 0){//如果链表为空,那么头节点和尾节点都是该新增节点 27 head = node; 28 tail = node; 29 size++; 30 }else{ 31 node.next = head; 32 head = node; 33 size++; 34 } 35 } 36 37 //链表尾新增节点 38 public void addTail(Object data){ 39 Node node = new Node(data); 40 if(size == 0){//如果链表为空,那么头节点和尾节点都是该新增节点 41 head = node; 42 tail = node; 43 size++; 44 }else{ 45 tail.next = node; 46 tail = node; 47 size++; 48 } 49 } 50 51 //删除头部节点,成功返回true,失败返回false 52 public boolean deleteHead(){ 53 if(size == 0){//当前链表节点数为0 54 return false; 55 } 56 if(head.next == null){//当前链表节点数为1 57 head = null; 58 tail = null; 59 }else{ 60 head = head.next; 61 } 62 size--; 63 return true; 64 } 65 //判断是否为空 66 public boolean isEmpty(){ 67 return (size ==0); 68 } 69 //获得链表的节点个数 70 public int getSize(){ 71 return size; 72 } 73 74 //显示节点信息 75 public void display(){ 76 if(size >0){ 77 Node node = head; 78 int tempSize = size; 79 if(tempSize == 1){//当前链表只有一个节点 80 System.out.println("["+node.data+"]"); 81 return; 82 } 83 while(tempSize>0){ 84 if(node.equals(head)){ 85 System.out.print("["+node.data+"->"); 86 }else if(node.next == null){ 87 System.out.print(node.data+"]"); 88 }else{ 89 System.out.print(node.data+"->"); 90 } 91 node = node.next; 92 tempSize--; 93 } 94 System.out.println(); 95 }else{//如果链表一个节点都没有,直接打印[] 96 System.out.println("[]"); 97 } 98 } 99 100 }
②、用双端链表实现队列
public class QueueLinkedList { 4 5 private DoublePointLinkedList dp; 6 7 public QueueLinkedList(){ 8 dp = new DoublePointLinkedList(); 9 } 10 public void insert(Object data){ 11 dp.addTail(data); 12 } 13 14 public void delete(){ 15 dp.deleteHead(); 16 } 17 18 public boolean isEmpty(){ 19 return dp.isEmpty(); 20 } 21 22 public int getSize(){ 23 return dp.getSize(); 24 } 25 26 public void display(){ 27 dp.display(); 28 } 29 30 }