我们知道,数组作为数据存储结构有一定的缺陷。在无序数组中,搜索时低效的;而在有序数组中,插入效率又很低;不管在哪一种数组中删除效率都很低。况且一个数组创建后,它的大小是无法改变的。
而链表可能是继数组之后第二种使用得最广泛的通用数据结构了。
这里主要来讨论并写一个单链表和双向链表。
顾名思义,单链表只能从表头到表尾的顺序,每个节点中保存了指向下一个节点的指针;
双向链表则可以反向遍历,因为节点中既保存了向后节点的指针,又保存了向前节点的指针。
由于链表结构相对简单,这里不再赘述,直接通过程序来查看它们常见的操作:
单链表实现
/**
* 单向链表
* 定义链表上的节点
*/
public class Link {
public int data;//节点的内容
public Link next;//下一个节点
//初始化
public Link(int data) {
this.data = data;
this.next = null;
}
//打印节点内容
public void displayLink(){
System.out.println("{" + data + "}");
}
}
/**
* 单向链表
*/
public class LinkedList {
private Link first;//第一个节点
private int nElem;//链表中节点数量
public LinkedList(){
first = null;
nElem = 0;
}
//添加头结点
public void insertFirst(int value){
Link newLink = new Link(value);
newLink.next = first;//newLink-->old first
first = newLink;//first-->newLink
nElem ++;
}
//删除头节点
public Link deleteFirst(){
if(isEmpty()){
System.out.println("链表为空");
return null;
}
Link temp = first;
first = first.next;
nElem --;
return temp;
}
/************************************************************
***下面是有序链表的插入***
***这样简单排序就可以用链表来实现,复杂度为O(N)
***定义一个方法,传入一个数组,
***在方法内,遍历数组并调用insert方法就可以将数组中的数据排好序
***********************************************************/
public void insert(int value){
Link newLink = new Link(value);//要插入的Link节点
Link previous = null;//前一个link节点
Link current = first;//因为是有序链表,从第一个开始
while(current != null && value > current.data){//当前link不是空,插入的数据大于当前link值
previous = current;//记录当前为前一个link节点
current = current.next;//当前link向下找
}
if(previous == null){//前一个为null证明只有没有插入link节点,直接插入就行
first = newLink;
}else {
previous.next = newLink;//插入这个link在小于value的link下,后边link为当前节点
}
newLink.next = current;//当前节点
nElem ++;//有序链表长度+1
}
//查找特定的节点
public Link find(int value){
Link current = first;//从第一个开始查找
while(current.data != value){
if(current.next == null){//下一个为空
return null;
}else{
current = current.next;//查找下一个节点
}
}
return current;
}
//删除特定的节点
public Link delete(int value){
Link current = first;
Link previous = first;//记录上一个Link,因为要删除节点,节点的指向要发生变化
while(current.data != value){
if(current.next == null){
return null;
}
previous = current;
current = current.next;
}
if(current == first){//如要要删除的是第一个
first = first.next;
}else{
previous.next = current.next;//删除link的上一个指向为当前link的下一个link
}
nElem --;
return current;
}
//查看链表中的数据
public void displayList(){
if(isEmpty()){//为空直接返回
System.out.println("链表为空!");
return;
}
Link current = first;
while(current != null){
current.displayLink();//调用link中的方法,打印当前link的值
current = current.next;
}
System.out.println(" ");
}
//链表是否为空
public boolean isEmpty(){
return (first == null);
}
//链表中节点个数
public int size(){
return nElem;
}
}
/*
测试有序单向链表
*/
public class LinkedListDemo {
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
linkedList.insert(1);
linkedList.insertFirst(2);
linkedList.insert(3);
linkedList.displayList();
System.out.println(linkedList.isEmpty());
System.out.println(linkedList.size());
linkedList.find(1).displayLink();
linkedList.deleteFirst();
linkedList.delete(3);
linkedList.displayList();
}
}
双向链表
/**
* 双向链表中的node
*/
public class Node {
public long data;//当前node的数据值
public Node next;//后一个node
public Node previous;//前一个node
public Node(long value) {
this.data = value;
this.next = null;
this.previous = null;
}
//打印节点中node值
public void displayLink(){
System.out.print(data + " ");
}
}
/**
* 双向链表的具体实现
*/
public class DoubleLinkedList {
private Node first;//头节点
private Node last;//尾节点
private int size;//链表长度
public DoubleLinkedList() {
this.first = null;
this.last = null;
this.size = 0;
}
//链表大小
public int size(){
return size;
}
//链表是否为空
public boolean isEmpty(){
return (first == null);
}
//插入头节点
public void insertFirst(long value){
Node newLink = new Node(value);
if(isEmpty()){
last = newLink;
}else {
//前first的node赋值为newLink
first.previous = newLink;//newLink <-- oldFirst.previous
//newLink的下一个node为first
newLink.next = first;//newLink.next --> first
}
first = newLink;//first --> newLink//第一个赋值为新插入的
size ++;
}
//插入尾节点
public void insertLast(long value){
Node newLink = new Node(value);
if(isEmpty()){
first = newLink;
}else{
last.next = newLink;
newLink.previous = last;
}
last = newLink;//最后一个赋值为新插入的
size ++;
}
//删除头节点
public Node deleteFirst(){
if(first == null){
System.out.println("链表为空");
return null;
}
Node temp = first;
if(first.next == null){//如果只有一个节点
last = null;
}else{
first.next.previous = null;//就是first的下一个node的前指针为空
}
first = first.next;//第一个为第一个的下一个
size --;
return temp;
}
//删除尾节点
public Node deleteLast(){
if(last == null){//最后一个节点为空,证明没有
System.out.println("链表为空");
return null;
}
Node temp = last;//暂存要删除的最后一个
if(last.previous == null){//只有一个节点
first = null;
}else{
last.previous.next = null;//last的前一个的next为null
}
last = last.previous;
size --;
return temp;
}
//在key后面插入值为value的新节点
public boolean insertAfter(long key,long value){
Node current = first;//从第一个开始
while(current.data != key){//对比传入的date
current = current.next;//下一个
if(current == null){//如果下一个为空,就是最后一个
System.out.println("不存在值为" + value + "的节点!");
return false;
}
}
if(current == last){//当前值为最后一个
insertLast(value);
}else{
Node newLink = new Node(value);//要插入的节点
newLink.next = current.next;//插入节点的下一个为匹配节点的下一个
current.next.previous = newLink;//匹配节点的前一个为新加入的节点
newLink.previous = current;//插入的前一个为匹配节点
current.next = newLink;//匹配节点的后一个节点为新加入的节点
size ++;
}
return true;//插入成功
}
//删除指定位置的节点
public Node deleteNode(long key){
Node current = first;//当前节点为第一个节点
while(current.data != key){
current = current.next;
if(current == null){
System.out.println("不存在该节点");
return null;
}
}
if(current == first){//如果匹配的是第一个
deleteFirst();
}else if(current == last){
deleteLast();//匹配的是最后一个
}else{
current.previous.next = current.next;//当前节点的前一个的后一个为 当前的后一个
current.next.previous = current.previous;//当前节点的后一个的前一个为 当前的前一个
size --;
}
return current;
}
//从头到尾遍历链表
public void displayForward(){
System.out.println("List(first --> last):");
System.out.print("[");
Node current = first;
while(current != null){
current.displayLink();//调用节点的显示方法
current = current.next;
}
System.out.println("]");
}
//从尾到头遍历链表
public void displayBackward(){
System.out.println("List(last --> first)");
System.out.print("[");
Node current = last;
while(current != null){
current.displayLink();
current = current.previous;
}
System.out.println("]");
}
}
/**
* 双向链表测试
*/
public class DoubleLinkedListDemo {
public static void main(String[] args) {
DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
doubleLinkedList.insertLast(9);
doubleLinkedList.insertFirst(1);
doubleLinkedList.insertAfter(1,2);
doubleLinkedList.insertAfter(2,3);
doubleLinkedList.insertAfter(9,10);
doubleLinkedList.displayBackward();
doubleLinkedList.displayForward();
System.out.println(doubleLinkedList.isEmpty());
System.out.println(doubleLinkedList.size());
//删除测试
doubleLinkedList.deleteFirst();
doubleLinkedList.deleteLast();
doubleLinkedList.deleteNode(3);
doubleLinkedList.displayBackward();
doubleLinkedList.displayForward();
}
}
其他:
用JAVA数组自己实现一个栈
用JAVA数组自己实现一个队列(普通队列以及优先级队列)
java中一些反射,collection,多线程,排序,红黑数,链表等总结整理