1、单向链表
1.1、链结点
在链表中,每一个数据项都被包含在一个链结点中(Link),每一个链接结点都包含一个对下一个链接点引用的字段。
但是,链表本身对象中包含一个对第一个Link连接点引用的字段。
1.2 链表的效率
如果仅仅是在表头插入数据或者删除表头的数据项的话,那么他的速度是比较快的,因为他只需要改变一两个引用值,所以花费O(1)的时间。但是,平均起来查找、删除、在指定链结点后面插入都需要对链结点进行搜索,搜索所需要进行O(N)次比较。在数组中执行这些操作也需要O(N)次比较,但是链表还是会快一点,因为插入和删除链表并不需要移动数据项,仅仅是改变一两个引用的指向而已
import android.util.Log; /** * @Description :链表链结点 */ public class Link { private int data;//数据对象数据项 private String name;//数据对象数据项 private Link next; //仅仅是对下一个Link的引用而已,并没有真正意义上持有对象的具体值, // 它只是计算机内存中的一个对象地址,它的主要作用只是用于告诉我们这个对象保存在内存中的什么位置而已 public int getData() { return data; } public void setData(int data) { this.data = data; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Link getNext() { return next; } public void setNext(Link next) { this.next = next; } public void displayLinkData() { Log.e("Test", data + " " + name); } }
package com.baidu.cloud.videoplayer.structure.link; /** * @Description :链表操作类 * @Created Time : yinrongwu on 2018/6/20. * @Author: YinRong.Wu@ubtrobot.com * @VerSion : Jimu_3.0 */ public class LinkList { Link first; /** * 判断链表是否为null * * @return */ public boolean isEmpty() { return first == null; } /** * 往列表中插入数据 * * @param id * @param name */ public void insertFirst(int id, String name) { Link newLink = new Link(); newLink.setData(id); newLink.setName(name); newLink.setNext(first); first = newLink; } /** * 根据某一数据项找到知道的链结点 * * @param id 这里可以根据id查找 也可以根据其他数据项查找 * @return */ public Link find(int id) { Link current = first; while (current.getData() != id) { if (current.getNext() == null) return null; else current = first.getNext(); } return current; } /** * 根据知道数据项删除某一个链结点 *@des 链表的删除方法和查找方法有点相像,它是先找到要删除的链结点, * 然后将要删除的链结点的上一个链结点和要删除的链结点的后一个链结点连起来 * @param key * @return */ public Link delete(int key) { Link current = first;//当前的连接点,首先将第一个连接点赋值给它 Link previous = first;//上一个链结点 while (current.getData() != key) { if (current.getNext() == null) return null; else { previous = current;//记录上一个链结点 current = current.getNext();//改变current为下一个连结点 } } if (current == first)//如果当前连接点等于第一个连结点 first = first.getNext();//那么就将链表头指向下一个链结点 else previous.setNext(current.getNext());//将上一个链结点的next 指向被删除的链结点的下一个链结点 return current; } /** * 删除链表的第一个数据项 * 该删除方法是insertFirst()的你操作, * 删除方法是通过把first重新指向第二个链结点 */ public Link deleteFirst() { Link temp = first; first = first.getNext(); return temp; } /** * 显示链表中的所有数据。 * 操作方式:从first开始,沿着引用链从一个链接点到下一个链接点 * current首先指向first,因为这个first正是第一个链结点的引用,然后通过current=current.next() * 来改变current,使它指向下一个链接点 */ public void displayList() { Link current = first; while (current != null) { current.displayLinkData(); current = current.getNext(); } } }
2.0 双端链表
FirstLastList.java
package com.baidu.cloud.videoplayer.structure.link; /** * @Description :双端链表 * @Created Time : yinrongwu on 2018/6/20. * @Author: YinRong.Wu@ubtrobot.com * @VerSion : Jimu_3.0 */ public class FirstLastList { private Link first; private Link last; public boolean isEmpty() { return first == null; } /** * 在链表头插入一个数据项 * * @param id * @param name * @return */ public Link insertFirst(int id, String name) { Link newLink = new Link(); newLink.setData(id); newLink.setName(name); if (isEmpty()) { last = newLink; first = newLink; } newLink.setNext(first); first = newLink; return newLink; } /** * 删除链表头部数据 */ public void deleteFirst() { if (first.getNext() == null) { last = null; } first = first.getNext(); } /** * 在链表数据尾插入一个数据项 * * @param id * @param name */ public void insertLast(int id, String name) { Link newLink = new Link(); newLink.setData(id); newLink.setName(name); if (isEmpty()) { first = newLink; last = newLink; } else last.setNext(newLink); last = newLink; } /** * 显示链表中的所有数据。 * 操作方式:从first开始,沿着引用链从一个链接点到下一个链接点 * current首先指向first,因为这个first正是第一个链结点的引用,然后通过current=current.next() * 来改变current,使它指向下一个链接点 */ public void displayList() { Link current = first; while (current != null) { current.displayLinkData(); current = current.getNext(); } } public Link delete(int id) { Link current = first; Link previous = first; while (current.getData() != id) { Link temp = current.getNext(); if (temp == null) return null; previous = current; current = current.getNext(); } if (current == first) first = first.getNext(); if (current == last) { last = previous; previous.setNext(null); } else previous.setNext(current.getNext()); return current; } }
3.0 使用链表来实现队列和栈
3.1 使用链表现实栈(链表代码和上面的一样)
/**
* @Description :使用链表实现堆
* @Created Time : yinrongwu on 2018/6/20.
* @Author: YinRong.Wu@ubtrobot.com
* @VerSion : Jimu_3.0
*/
public class LinkStack {
private LinkList linkList;
public LinkStack() {
this.linkList = new LinkList();
}
public void push(int id) {
linkList.insertFirst(id, "");
}
public void pop() {
linkList.deleteFirst();
}
public boolean isEmpty() {
return linkList.isEmpty();
}
public void displayStack() {
linkList.displayList();
}
3.2使用链表实现队列(使用双端链表实现)
/**
* @Description :使用链表实现队列
* @Created Time : yinrongwu on 2018/6/20.
* @Author: YinRong.Wu@ubtrobot.com
*/
public class LinkQueue {
private FirstLastList mFirstLastList;
public LinkQueue() {
mFirstLastList = new FirstLastList();
}
/**
* 往队列中插入数据
*
* @param id
*/
public void insert(int id) {
mFirstLastList.insertLast(id, "");
}
public void remove() {
mFirstLastList.deleteFirst();
}
public void displayLinkQueue() {
mFirstLastList.displayList();
}
}
4.0有序链表
4.1有序链表的效率
有序链表的插入和删除某一数据项需要最多O(N)次比较 (平均N/2),但是如果是删除最小或者最大值的话,只需要O(1)的时间,因为它总在表头。如果一个应用需要频繁的存取最小或者最大值而且不需要快速的插入,那么有序链表是一个不错的方案选择,例如,优先级队列可以用优先链表来实现。
package com.example.yinrongwu.datastructures.structure.link; import android.util.Log; /** * @Description : 有序链表操作类 * @Created Time : yinrongwu on 2018/7/12. */ public class LinkListOperation { private Link firstLink; private Link lastLink; /** * 判断链表是否为null * * @return */ public boolean isEmpty() { return firstLink == null; } /** * 有序列表插入排序 * * @param value */ public void inser(int value) { Link link = new Link(value); Link previous = null; Link current = firstLink; while (current != null && value > current.getId()) { previous = current; current = current.getNext(); } if (previous == null) { firstLink = link; } else previous.setNext(link); link.setNext(current); } /** * 删除链表头的数据 */ public Link remove(){ Link temp=firstLink; firstLink=firstLink.getNext(); return temp; } /** * 打印链表中的数据 */ public void displayList() { Link current = firstLink; Log.e("TestLog", "------------------------"); while (current != null) { current.display(); current = current.getNext(); } Log.e("TestLog", "------------------------"); } }
链表测试:
package com.example.yinrongwu.datastructures.structure; import com.example.yinrongwu.datastructures.structure.link.LinkListOperation; /** * @Description : * @Created Time : yinrongwu on 2018/7/12. */ public class StructureTest { /** * 有序列表测试 */ public void testLink_1(){ LinkListOperation linkListOperation=new LinkListOperation(); linkListOperation.inser(5); linkListOperation.inser(6); linkListOperation.inser(9); linkListOperation.inser(1); linkListOperation.inser(0); linkListOperation.inser(3); linkListOperation.inser(2); linkListOperation.displayList(); } }
5.0双向链表
双向链表的优点解决了传统链表反向遍历困难的问题。
双向链表的缺点,每次插入或者删除链结点的时候,都有处理四个链结点的引用,而不是两个。两个连接前一个链结点,两个连接后一个链结点。另外多了两个引用自然占用的空间也变大了一点。
代码示例:
DoublyLink.java
package com.example.yinrongwu.datastructures.structure.link; /** * * @Description : 双向链表链结点 * @Created Time : yinrongwu on 2018/7/12. */ public class DoublyLink { private int id; private DoublyLink next; private DoublyLink previous; public DoublyLink(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } public DoublyLink getNext() { return next; } public void setNext(DoublyLink next) { this.next = next; } public DoublyLink getPrevious() { return previous; } public void setPrevious(DoublyLink previous) { this.previous = previous; } }
DoublyLinkedListOperation.java
package com.example.yinrongwu.datastructures.structure.link;
import android.util.Log;
/**
* @Description :双向链表操作类
* @Created Time : yinrongwu on 2018/7/12.
*/
public class DoublyLinkedListOperation {
private DoublyLink first;
private DoublyLink last;
/**
* 判断链表是否为null
*
* @return
*/
public boolean isEmapty() {
return first == null;
}
/**
* 在链表头插入数据
*
* @param id
*/
public void insertFirst(int id) {
DoublyLink newDoublyLink = new DoublyLink(id);
if (isEmapty()) {
first = newDoublyLink;
last = newDoublyLink;
} else {
first.setPrevious(newDoublyLink);
newDoublyLink.setNext(first);
first = newDoublyLink;
}
}
/**
* 在链表尾插入数据
*
* @param id
*/
public void insertLast(int id) {
DoublyLink doublyLink = new DoublyLink(id);
if (isEmapty()) {
first = doublyLink;
last = doublyLink;
} else {
last.setNext(doublyLink);
doublyLink.setPrevious(last);
last = doublyLink;
}
}
/**
* 有序插入数据
*
* @param id
*/
public DoublyLink insertSort(int id) {
DoublyLink temp = first;
DoublyLink previous=null;
DoublyLink doublyLink = new DoublyLink(id);
while (temp!=null&&temp.getId()<id) {
previous=temp;
temp = temp.getNext();
}
if(previous==null){
first=doublyLink;
}else {
previous.setNext(doublyLink);
}
doublyLink.setPrevious(previous);
doublyLink.setNext(temp);
if(temp!=null){
temp.setPrevious(doublyLink);
}else {
last=doublyLink;
}
return doublyLink;
}
/**
* 删除表头
*
* @return
*/
public DoublyLink deleteFirst() {
DoublyLink temp = first;
if (temp == null)
return null;
DoublyLink firstNext = first.getNext();
if (first.getNext() == null) {
last = null;
first = null;
} else {
firstNext.setPrevious(null);
}
first = firstNext;
return temp;
}
/**
* 删除链表尾
*
* @return
*/
public DoublyLink deleteLast() {
DoublyLink temp = last;
if (temp == null) return null;
DoublyLink previous = last.getPrevious();
if (first.getNext() == null) {
first = null;
last = null;
} else
last.getPrevious().setNext(null);
last = previous;
return temp;
}
/**
* 删除特定值的链结点
*
* @param id
*/
public void deleteLink(int id) {
DoublyLink temp = first;
while (temp != null) {
if (temp.getId() == id) {
DoublyLink per = temp.getPrevious();
DoublyLink next = temp.getNext();
if (first == temp) {
temp.setPrevious(null);
first = next;
} else if (temp == last) {
per.setNext(null);
last = per;
} else {
per.setNext(next);
next.setPrevious(per);
}
}
temp = temp.getNext();
}
}
/**
* 顺向遍历
*/
public void displayForward() {
DoublyLink temp = first;
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("{ ");
while (temp != null) {
stringBuffer.append(temp.getId() + " ");
temp = temp.getNext();
}
stringBuffer.append(" }");
Log.e("TestLog", stringBuffer.toString());
}
/**
* 逆向遍历
*/
public void displayBackward(){
DoublyLink doublyLink=last;
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("{ ");
while (doublyLink!=null){
stringBuffer.append(doublyLink.getId()+" ");
doublyLink=doublyLink.getPrevious();
}
stringBuffer.append(" }");
Log.e("TestLog", stringBuffer.toString());
}
}
测试:
public void testLink_2(){
DoublyLinkedListOperation doublyLinkedListOperation=new DoublyLinkedListOperation();
doublyLinkedListOperation.insertFirst(1);
doublyLinkedListOperation.insertFirst(2);
doublyLinkedListOperation.insertFirst(3);
doublyLinkedListOperation.insertFirst(4);
doublyLinkedListOperation.insertLast(5);
doublyLinkedListOperation.insertLast(6);
doublyLinkedListOperation.insertLast(7);
doublyLinkedListOperation.insertLast(8);
doublyLinkedListOperation.displayForward();
doublyLinkedListOperation.displayBackward();
Log.e("TestLog","------------------------------------");
doublyLinkedListOperation.deleteFirst();
doublyLinkedListOperation.deleteFirst();
doublyLinkedListOperation.deleteFirst();
doublyLinkedListOperation.deleteFirst();
doublyLinkedListOperation.displayForward();
Log.e("TestLog","------------------------------------");
doublyLinkedListOperation.deleteLast();
// doublyLinkedListOperation.deleteLast();
// doublyLinkedListOperation.deleteLast();
// doublyLinkedListOperation.deleteLast();
doublyLinkedListOperation.displayForward();
Log.e("TestLog","------------------------------------");
}