(数据结构)线性表之链表,java实现

来源:互联网 发布:win7隐藏网络连接 编辑:程序博客网 时间:2024/05/16 16:08

上一篇文章介绍了线性表中的顺序表,今天介绍线性表的链表。

链式存储结构的特点

顺序存储结构,是在内存中分配一组地址连续的地址来存储线性表中的元素,需要一次性分配连续的一片空间,链表采用一组地址任意的存储单元存放线性表中的数据元素,所以需要在每个数据元素中保存一个引用下一个元素的引用。

对比线性表的两种实现

 hk

顺序表

链表

 

空间

需要在内存中静态分配一组地址连续的内存,数组长度固定,所以总有一些数组元素被浪费

存储地址动态分布,空间不会被浪费,但需要一些空间来保存下一个或上一个结点的指针,所以也要牺牲一部分空间

 

时间

顺序表中的逻辑顺序与物理存储顺序相同,所以查找,读取性能很好,插入删除时,需要移动结点之后的元素,数组扩容时,需要复制数组元素,所以插入删除性能较差。

链表采用链式结构保存表内的元素,插入删除性能很好,查找性能不如顺序表

 

1.单链表的简单实现:
package xxx.hk.linearlist;public class LinkList<T> {// 链表的长度private int size = 0;// 链表的头部private Node header;// 链表的尾部private Node tail;// 链表结点private class Node {// 结点的值private T data;// 下一个结点private Node next;public Node(T data, Node next) {super();this.data = data;this.next = next;}}public LinkList() {header = null;tail = null;}public LinkList(T data) {header = new Node(data, null);tail = header;size = 1;}/** * 根据索引值返回结点 *  * @param index * @return 该索引的结点 */public Node getNodeByIndex(int index) {if (index < 0 || index > size - 1) {throw new IndexOutOfBoundsException("下标越界异常");}Node currentNode = header;for (int i = 0; i < size && header != null; i++, currentNode = currentNode.next) {if (i == index) {return currentNode;}}return null;}/** * 根据索引值返回结点的值 *  * @param index * @return 结点的值 */public T get(int index) {return getNodeByIndex(index).data;}/** * 尾插法插入结点 *  * @param data */public void add(T data) {Node node = new Node(data, null);// 如果链表为空if (header == null) {header = node;tail = header;} else {tail.next = node;tail = node;}size++;}/** * 头插法插入结点 *  * @param data */public void addHead(T data) {Node node = new Node(data, null);// 如果链表为空if (tail == null) {header = node;tail = header;} else {node.next = header;header = node;}size++;}/** * 插入到索引处 * @param data * @param index */public void insert(T data, int index) {// 插入位置小于0 插入到第一个if (index <= 0) {addHead(data);// 插入位置大于链表长度或者链表为空,插入到最后一个} else if (index >= size) {add(data);} else {//得到该索引前一个结点Node preNode = getNodeByIndex(index-1);//修改next所指的结点preNode.next = new Node(data, preNode.next);size++;}}/** * 删除索引处的结点 * @param index * @return 删除结点的值 */public T deleteByIndex(int index){if(index<0||index>size){throw new IndexOutOfBoundsException("下标越界异常");}Node delNode = null;//如果删除头结点if(index==0){delNode = header;header = header.next;}else{Node preNode = getNodeByIndex(index-1);delNode = preNode.next;preNode.next = delNode.next;}size--;return delNode.data;}/** * 删除最后一个 * @return */public T delete(){return deleteByIndex(size-1);}/** * 根据值找到索引值 * @param data * @return 索引值 为找到则为-1 */public int getIndex(T data){if(header==null){return -1;}Node current = header;for(int i=0;i<size&¤t!=null;i++,current=current.next){if(current.data.equals(data)){return i;}}return -1;}/** * 是否为空 * @return true/false */public boolean isEmpty(){return size==0;}/** * 清空链表 */public void clear(){header = null;tail = null;size = 0;}/** * 链表的长度 * @return */public int length(){return size;}/*  * 重写的tostring方法 * @see java.lang.Object#toString() */@Overridepublic String toString(){if(isEmpty()){return "[]";}else{StringBuilder sb = new StringBuilder("[");for(Node current = header;current!=null;current = current.next){sb.append(current.data+",");}int len = sb.length();return sb.delete(len-1,len).append("]").toString();}}//测试public static void main(String[] args) {LinkList<String> list = new LinkList<>();list.add("hk");System.out.println(list.length());System.out.println(list);list.add("wyh");list.add("123");System.out.println(list.length());System.out.println(list);System.out.println(list.isEmpty());list.insert("aa", 1);System.out.println(list);list.delete();System.out.println(list);list.deleteByIndex(1);System.out.println(list);System.out.println(list.getIndex("hk"));list.clear();System.out.println(list);}}

2.循环链表:尾结点的下一结点指针指向头结点
3.双向链表:每个元素结点包含 上一个结点和下一个结点的引用
package xxx.hk.linearlist;public class DuLinkList<T> {// 链表长度private int length;// 头结点private Node header;// 尾结点private Node tail;// 结点内部类private class Node {// 结点的值T data;// 上一个结点Node prev;// 下一个结点Node next;public Node(T data, DuLinkList<T>.Node prev, DuLinkList<T>.Node next) {this.data = data;this.prev = prev;this.next = next;}}public DuLinkList() {header = null;tail = null;}public DuLinkList(T data) {header = new Node(data, null, null);tail = header;length = 1;}public DuLinkList(T data1, T data2, Node head, Node tail) {header = new Node(data1, null, tail);tail = new Node(data2, header, null);length = 2;}/** * 尾插法插入结点 *  * @param data */public void add(T data) {// 链表为空if (header == null) {header = new Node(data, null, null);tail = header;length++;} else {DuLinkList<T>.Node node = new Node(data, tail, null);tail.next = node;tail = node;length++;}}/** * 头插法插入结点 *  * @param data */public void addAtHead(T data) {if (header == null) {header = new Node(data, null, null);tail = header;length++;} else {DuLinkList<T>.Node node = new Node(data, null, header);header.prev = node;header = node;length++;}}/** * 根据索引值返回结点 *  * @param index * @return 索引值对应的结点 */public Node get(int index) {if (index < 0 || index > length - 1) {throw new IndexOutOfBoundsException("下标越界");}// 从链首开始找if (index <= length / 2) {Node current = header;for (int i = 0; i < length && current != null; i++, current = current.next) {if (index == i) {return current;}}} else { // 从链尾开始找Node current = tail;for (int i = length - 1; i >= 0 && current != null; i--, current = current.prev) {if (index == i) {return current;}}}return null;}/** * 在指定位置插入元素结点 *  * @param data * @param index */public void addAtIndex(T data, int index) {// 插入到链首if (index == 0) {addAtHead(data);// 插入到链尾} else if (index == length) {add(data);} else {Node node = get(index);Node newNode = new Node(data, node.prev, node);node.prev = newNode;length++;}}/** * 删除指定位置的结点 *  * @param index * @return 删除结点的值 */public T delAtIndex(int index) {if (index == 0) {return removeFirst();} else if (index == length - 1) {return remove();} else {Node node = get(index);T data = node.data;node.prev.next = node.next;node.next.prev = node.prev;node = null;length--;return data;}}/** * 删除最后一个 *  * @return 删除结点的值 */public T remove() {// 如果链表不为空if (tail != null) {T data = tail.data;tail = tail.prev;tail.next = null;length--;return data;}return null;}/** * 删除第一个 *  * @return 删除结点的值 */public T removeFirst() {// 如果链表不为空if (header != null) {T data = header.data;header = header.next;header.prev = null;length--;return data;}return null;}/** * 判断链表是否为空 * @return true/false */public boolean isEmpty(){return length>0?false:true;}//返回链表的长度public int length(){return length;}/*  * 打印链表 * @see java.lang.Object#toString() */@Overridepublic String toString() {if(isEmpty()){return "[]";}else{StringBuilder sb = new StringBuilder("[");Node current = header;for(int i = 0;i<length&¤t!=null;i++,current=current.next){sb.append(current.data+",");}//删除最后一个,sb.append("]").delete(sb.length()-2, sb.length()-1);return sb.toString();}}/** * 倒叙打印链表 * @return String 链表的所有节点的值s */public String reverseToString(){if(isEmpty()){return "[]";}else{StringBuilder sb = new StringBuilder("[");Node current = tail;for(int i = length;i>0&¤t!=null;i++,current=current.prev){sb.append(current.data+",");}//删除最后一个,sb.append("]").delete(sb.length()-2, sb.length()-1);return sb.toString();}}public static void main(String[] args) {DuLinkList<Integer> duLinkList = new DuLinkList<>();/*System.out.println(duLinkList.length);System.out.println(duLinkList.isEmpty());*/duLinkList.add(1);/*System.out.println(duLinkList.length);System.out.println(duLinkList.isEmpty());*/duLinkList.add(2);duLinkList.addAtHead(0);duLinkList.addAtIndex(-1, 0);duLinkList.addAtIndex(3,4);//duLinkList.remove();//duLinkList.delAtIndex(0);duLinkList.delAtIndex(4);System.out.println(duLinkList.toString());System.out.println(duLinkList.reverseToString());}}

顺序表、链表分别对应java中的 ArrayList、LinkedList的实现,可以参考源代码进行模仿改进。