java线性表学习笔记(二)
链表中的每一个元素都包含一个称为节点的结构,每向链表中增加一个元素,就会产生一个与之相关的节点,每个节点与它相邻的节点相连接(这是基础吧,不过在看c的时候没认真看,呼)。
定义节点类如下(使用了泛型,下面有个简单的具体实例):
class Node<E>{ E element ; Node<E> next; public Node(E e){ element = e; } }
下面讲解一个储存3个元素的链表的例子,每一个节点储存一个字符串;
1、先声明head(指向第一个节点) 和tai(指向最后一个节点),刚开始时都是null
Node<E> head = null; Node<E> tail = null; //链表为空
2、追加第一个节点
head = new Node<E>("Chicgo"); last = head;
3、追加第二个节点
tail.next = new Node<E>("Denver"); tail = tail.next;
3、追加第三个节点
tail.next = new Node<E>("Dallas"); tail = tail.next;
每一个节点都包含元素和一个名为next的数据域,next指向下一个元素。如果元素是链表中的最后一个元素。则它的next所包含的为null,用这个特性可以检测某个节点是否为最后一个节点,例如下面的遍历程序:
Node current = head; while()current !=null){ System.out.println(current.element); current = current.next; }
下面就结合上面的知识给个简单的int类型事例:
//一个节点类,每一个元素都包含了一个称为节点的结构 public class Node{ int element; Node next ; public Node(int n){ //元素赋值 element = n; } public static void main(String[] args) { Node head , tail; //申明head和tail head = new Node(1); //插入第一个元素 tail = head; //head和tail在一起 System.out.println(head.element); //输出第一个元素 tail.next = new Node(2); //插入第二个元素 tail = tail.next; tail.next =new Node(3); tail = tail.next; Node current = head ; while (current != null){ //遍历寻遍输出 System.out.print(current.element); current = current.next; } } }
java中有提供LinkedList的类,可以通过导入 java.util.LinkedList来使用,不过书本上有教我们写一个自己的MyLinkedList,便于理解,这对我们掌握链表还是很有必要的。下面我们可以来仔细研究一下MyLinkedList了,有好多方法,不像MyArrayList容易理解,书本上也只是讲了几个方法,剩下的就自己去理解了,也不是很难,这里讲3个吧,就当练习打字。
(补充:head始终指向链表的第一个节点,而tail则始终指向最后一个节点)
1、实现addFirst(e)方法,就是创建第一个节点:
//创建一个包含e元素节点,并放在第一个节点 public void addFirst(E e) { Node<E> newNode = new Node<E>(e); // 创建一个的节点 newNode.next = head; //新节点的next数据域指向head head = newNode; // head 指向新的节点 size++; if (tail == null) // 若链表为空,则head和tail都指向新节点 tail = head; }
(书本上的那个图很好看,但是画不下来==)
2、实现add(index,e)方法,当index为0或则是在最后一个元素时就不说了,直接调用方法addFirst(e)或则addLast(e)就行了,若插入到中间时,假设为current和temp节点之间,则首先从head开始前进找到current的next,并被新节点赋给它,在把新节点的next指向temp,画个图就很容易理解了。
public void add(int index, E e) { if (index == 0) { addFirst(e); } else if (index >= size) { addLast(e); } else { Node<E> current = head; for (int i = 1; i < index; i++) { current = current.next; } Node<E> temp = current.next; current.next = new Node<E>(e); (current.next).next = temp; size++; } }
3、实现removeLast()方法,如果链表为空就返回null,如果只有一个节点就销毁并且head和tail都变为null,否则最后一个节点销毁,tail指向倒数第二个节点,size减一。
public E removeLast() { if (size == 0) { return null; } else if (size == 1) { Node<E> temp = head; head = tail = null; size = 0; return temp.element; } else { Node<E> current = head; //要从head开始遍历,增加了时间 for (int i = 0; i < size - 2; i++) { current = current.next; //找到倒数第二个节点 } Node<E> temp = tail; //临时引用temp tail = current; tail.next = null; size--; return temp.element; } }
最后在给出MyLinkedList的实现(仅有部分方法实现,还有部分,做作业):
1 public class MyLinkedList<E> extends MyAbstractList<E> { 2 private Node<E> head, tail; 3 4 //创建默认链表 5 public MyLinkedList() { 6 } 7 8 public MyLinkedList(E[] objects) { 9 super(objects); 10 } 11 12 //获得链表的头 13 public E getFirst() { 14 if (size == 0) { 15 return null; 16 } 17 else { 18 return head.element; 19 } 20 } 21 22 //获得链表的尾 23 public E getLast() { 24 if (size == 0) { 25 return null; 26 } 27 else { 28 return tail.element; 29 } 30 } 31 32 //创建一个包含e元素节点,并放在第一个节点 33 public void addFirst(E e) { 34 Node<E> newNode = new Node<E>(e); // 创建一个的节点 35 newNode.next = head; //新节点的next数据域指向head 36 head = newNode; // head 指向新的节点 37 size++; 38 39 if (tail == null) // 若链表为空,则head和tail都指向新节点 40 tail = head; 41 } 42 43 //创建一个包含e元素节点,并放在最后一个节点 44 public void addLast(E e) { 45 Node<E> newNode = new Node<E>(e); 46 47 if (tail == null) { 48 head = tail = newNode; 49 } 50 else { 51 tail.next = newNode; 52 tail = tail.next; 53 } 54 size++; 55 } 56 57 58 //将一个元素插入到链表的指定下标处 59 public void add(int index, E e) { 60 if (index == 0) { 61 addFirst(e); 62 } 63 else if (index >= size) { 64 addLast(e); 65 } 66 else { 67 Node<E> current = head; 68 for (int i = 1; i < index; i++) { 69 current = current.next; 70 } 71 Node<E> temp = current.next; 72 current.next = new Node<E>(e); 73 (current.next).next = temp; 74 size++; 75 } 76 } 77 78 //删除链表中的的首个元素 79 public E removeFirst() { 80 if (size == 0) { 81 return null; 82 } 83 else { 84 Node<E> temp = head; 85 head = head.next; 86 size--; 87 if (head == null) { 88 tail = null; 89 } 90 return temp.element; 91 } 92 } 93 94 //删除最后一个元素 95 public E removeLast() { 96 if (size == 0) { 97 return null; 98 } 99 else if (size == 1) { 100 Node<E> temp = head; 101 head = tail = null; 102 size = 0; 103 return temp.element; 104 } 105 else { 106 Node<E> current = head; //要从head开始遍历,增加了时间 107 for (int i = 0; i < size - 2; i++) { 108 current = current.next; //找到倒数第二个节点 109 } 110 111 Node<E> temp = tail; //临时引用temp 112 tail = current; 113 tail.next = null; 114 size--; 115 return temp.element; 116 } 117 } 118 119 //删除指定下标的元素 120 public E remove(int index) { 121 if (index < 0 || index >= size) { 122 return null; 123 } 124 else if (index == 0) { 125 return removeFirst(); 126 } 127 else if (index == size - 1) { 128 return removeLast(); 129 } 130 else { 131 Node<E> previous = head; 132 133 for (int i = 1; i < index; i++) { 134 previous = previous.next; 135 } 136 137 Node<E> current = previous.next; 138 previous.next = current.next; 139 size--; 140 return current.element; 141 } 142 } 143 144 public String toString() { 145 StringBuilder result = new StringBuilder("["); 146 147 Node<E> current = head; 148 for (int i = 0; i < size; i++) { 149 result.append(current.element); 150 current = current.next; 151 if (current != null) { 152 result.append(", "); // 插入歌逗号 153 } 154 else { 155 result.append("]"); // 插入] 156 } 157 } 158 159 return result.toString(); 160 } 161 162 //清空 163 public void clear() { 164 head = tail = null; 165 } 166 167 168 /** Return true if this list contains the element o */ 169 public boolean contains(E o) { 170 System.out.println("Implementation left as an exercise"); 171 return true; 172 } 173 174 /** Return the element from this list at the specified index */ 175 public E get(int index) { 176 System.out.println("Implementation left as an exercise"); 177 return null; 178 } 179 180 /** Return the index of the head matching element in this list. 181 * Return -1 if no match. */ 182 public int indexOf(E o) { 183 System.out.println("Implementation left as an exercise"); 184 return 0; 185 } 186 187 /** Return the index of the last matching element in this list 188 * Return -1 if no match. */ 189 public int lastIndexOf(E o) { 190 System.out.println("Implementation left as an exercise"); 191 return 0; 192 } 193 194 /** Replace the element at the specified position in this list 195 * with the specified element. */ 196 public Object set(int index, E o) { 197 System.out.println("Implementation left as an exercise"); 198 return null; 199 } 200 201 202 private static class Node<E> { 203 E element; 204 Node<E> next; 205 206 public Node(E element) { 207 this.element = element; 208 } 209 } 210 }
在附上一个测试程序:
1 public class TestLinkedList { 2 /** Main method */ 3 public static void main(String[] args) { 4 // Create a list for strings 5 MyLinkedList<String> list = new MyLinkedList<String>(); 6 7 // Add elements to the list 8 list.add("America"); // Add it to the list 9 System.out.println("(1) " + list); 10 11 list.add(0, "Canada"); // Add it to the beginning of the list 12 System.out.println("(2) " + list); 13 14 list.add("Russia"); // Add it to the end of the list 15 System.out.println("(3) " + list); 16 17 list.addLast("France"); // Add it to the end of the list 18 System.out.println("(4) " + list); 19 20 list.add(2, "Germany"); // Add it to the list at index 2 21 System.out.println("(5) " + list); 22 23 list.add(5, "Norway"); // Add it to the list at index 5 24 System.out.println("(6) " + list); 25 26 list.add(0, "Poland"); // Same as list.addFirst("Poland") 27 System.out.println("(7) " + list); 28 29 // Remove elements from the list 30 list.remove(0); // Same as list.remove("Australia") in this case 31 System.out.println("(8) " + list); 32 33 list.remove(2); // Remove the element at index 2 34 System.out.println("(9) " + list); 35 36 list.remove(list.size() - 1); // Remove the last element 37 System.out.println("(10) " + list); 38 } 39 }
关于MyArrayList和MyLinkedList的方法的复杂度,看下面的图