码迷,mamicode.com
首页 > 其他好文 > 详细

链表简介

时间:2018-07-29 22:27:39      阅读:186      评论:0      收藏:0      [点我收藏+]

标签:info   属性   ext   一个   def   增加   复杂度   技术   print   

什么是链表?

链表就是链式存储的线性表。根据指针域的不同,链表分为单向链表、双向链表、循环链表等等

链表属性

  • 相邻元素之间通过指针链接
  • 最后一个元素的后继指针为NULL
  • 在程序执行过程中,链表的长度可以增加或缩小
  • 链表的空间能够按需分配
  • 没有内存空间的浪费

优点:

  • 插入和删除时不需移动其他元素, 只需改变指针。
  • 链表各个节点在内存中空间不要求连续!空间利用率高。

优点:

  • 访问数组元素效率低。

单向链表

结构

技术分享图片

单向链表的类型声明

public class ListNode {
    private int data;
    private ListNode next;

    public ListNode(int data){
        this.data = data;
    }
    
    public void setData(int data){
        this.data = data;
    }
    public int getData(){
        return data;
    }
    public void setNext(ListNode next){
        this.next = next;
    }
    public ListNode getNext(){
        return this.next;
    }
}

遍历单向链表

int ListLength(ListNode headNode){
    int length = 0;
    ListNode current = headNode;
    while(current != null){
        length++;
        current = current.getNext();
    }
    return length;
}

时间复杂度为O(n), 空间复杂度O(1)

单向链表插入元素

单向链表插入操作有以下三种情况: 表头插入,表尾插入,中间插入

ListNode InsertInLinkedList(ListNode headNode, ListNode nodeToInsert, int position){
    if(headNode == null){  // 链表为空时插入
        return nodeToInsert;
    }
    int size = ListLength(headNode);
    if(position > size+1 || position <1){
        System.out.println("Position of nodeToInsert is invalid");
        return headNode;
    }
    
    if(position == 1){  // 在链表开头插入
        nodeToInsert.setNext(headNode);
        return nodeToInsert;
    }else{  // 在链表中间或末尾插入
        ListNode previousNode = headNode;
        int count = 1;
        while(count < position-1){
            previousNode = previousNode.getNext();
            count++;
        }
        ListNode currentNode = previousNode.getNext();
        nodeToInsert.setNext(currentNode);
        previousNode.setNext(nodeToInsert);
    }
    return headNode;
}

时间复杂度为O(n), 空间复杂度O(1)

链表删除元素

单向链表插入操作有以下三种情况:删除表头元素,删除表尾元素, 删除中间元素

ListNode DeleteNodeFromLinkedList(ListNode headNode, int position){
    int size = ListLength(headNode);
    if(position > size || position < 1){
        return headNode;
    }
    
    if(position == 1){
        ListNode currentNode = headNode.getNext();
        headNode = null;
        return currentNode;
    }else{
        ListNode previousNode = headNode;
        int count = 1;
        while (count < position){
            previousNode = previousNode.getNext();
            count++;
        }
        ListNode currentNode = previousNode.getNext();
        previousNode.setNext(currentNode.getNext());
        currentNode = null;
    }
    return headNode;
}

时间复杂度为O(n), 空间复杂度O(1)

删除单向链表

void DeleteLinkedList(ListNode headNode){
    ListNode auxilaryNode, iterator = headNode;
    while (iterator != null){
        auxilaryNode = iterator.getNext();
        iterator = null;
        iterator = auxilaryNode;
    }
}

时间复杂度为O(n), 空间复杂度O(1)

双向链表

优点:

对于链表中一个给的的结点,可以从两个方向进行操作。

缺点:

  • 每个结点需要再添加一个额外的指针,因此需要更多的空间开销
  • 结点的插入或者删除更加费时

结构

技术分享图片

双向链表类型声明

public class DLLNode {
    private int data;
    private DLLNode next;
    private DLLNode previous;
    public DLLNode(int data){
        this.data = data;
    }
    
    public void setData(int data){
        this.data = data;
    }
    public int getData(){
        return data;
    }
    public void setNext(DLLNode next){
        this.next = next;
    }
    public DLLNode getNext(){
        return this.next;
    }
    public void setPrevious(DLLNode previous){
        this.previous = previous;
    }
    public DLLNode getPrevious(){
        return this.previous;
    }
}

双向链表插入元素

单向链表插入操作有以下三种情况:表头插入,表尾插入, 中间插入

DLLNode DLLInsert(DLLNode headNode, DLLNode nodeToInsert, int position) {
    // 链表为空时插入
    if (headNode == null) {
        return nodeToInsert;
    }
    int size = ListLength(headNode);
    if (position > size + 1 || position < 1) {
        System.out.println("Position of nodeToInsert is invalid");
        return headNode;
    }

    if (position == 1) { // 在链表开头插入
        nodeToInsert.setNext(headNode);
        headNode.setPrevious(nodeToInsert);

    } else {// 在链表中间或末尾插入
        DLLNode previousNode = headNode;
        int count = 1;
        while (count < position - 1) {
            previousNode = previousNode.getNext();
            count++;
        }
        DLLNode currentNode = previousNode.getNext();
        nodeToInsert.setNext(currentNode);
        if (currentNode != null) {
            currentNode.setPrevious(nodeToInsert);
        }
        previousNode.setNext(nodeToInsert);
        nodeToInsert.setPrevious(previousNode);
    }
    return headNode;
}

时间复杂度为O(n), 空间复杂度O(1)

双向链表删除元素

单向链表插入操作有以下三种情况:删除表头元素,删除表尾元素,删除中间元素

DLLNode DDLDelete(DLLNode headNode, int position){
    int size = ListLength(headNode);
    // 如果被删除位置不在链表长度范围内,报错并返回
    if(position > size || position < 1){
        System.out.println("Position of node to delete is invalid.");
    }

    if(position == 1){ //删除链表的第一个结点
        DLLNode currentNode = headNode.getNext();
        headNode = null;
        currentNode.setPrevious(null);
        return currentNode;
    }else { //删除中间或表尾结点
        DLLNode previousNode = headNode;
        int count = 1;
        while (count < position - 1){
            previousNode = previousNode.getNext();
            count++;
        }
        DLLNode currentNode = previousNode.getNext();
        DLLNode laterNode = currentNode.getNext();
        previousNode.setNext(laterNode);
        if(laterNode != null){
            // 如果被删除结点的后继结点不是null结点,那么设置其前驱指针指向被删除结点的前驱结点
            laterNode.setPrevious(previousNode);
        }
        currentNode = null;
    }
    return headNode;
}

时间复杂度为O(n), 空间复杂度O(1)

循环链表

结构

技术分享图片

类型声明(同单向链表

public class CLLNode {
    private int data;
    private CLLNode next;

    public CLLNode(int data) {
        this.data = data;
    }

    public void setData(int data) {
        this.data = data;
    }

    public int getData() {
        return data;
    }

    public void CLLNode(CLLNode next) {
        this.next = next;
    }

    public CLLNode getNext() {
        return this.next;
    }
}

循环链表的长度

int CircularListLength(CLLNode headNode) {
    int length = 0;
    CLLNode currentNode = headNode;
    while (currentNode != null){
        length++;
        currentNode = currentNode.getNext();
        if(currentNode == headNode){
            break;
        }
    }
    return length;
}

松散链表

松散链表是单向链表的简单变种。松散链表中的每个结点存储多个元素(简称为块)。而每个块中的所有结点由循环链表链接在一起。

结构

技术分享图片

链表简介

标签:info   属性   ext   一个   def   增加   复杂度   技术   print   

原文地址:https://www.cnblogs.com/ifengliang/p/9384841.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!