数据结构-链表

链表是面试常考问题

结构:

由指针把若干个节点连接成链状结构

包括创建、插入、删除等操作

链表是一种动态数据结构,是因为在创建链表时,无需知道链表长度

当插入一个节点时,我们只需要微信节点分配内存,然后调整指针的指向来确保新节点被连接到链表中

内存分配不是在创建链表时一次性完成的,而是每添加一个节点分配一次内存

没有闲置的内存

单向链表的节点定义:

class ListNode{
  int value;
  ListNode nextNode;
}

往该链表的末尾添加一个节点的代码:

class ListNode {
    int value;
    ListNode nextNode;
    ListNode(int x) { value = x; }
}

public class linkedList{
    public static void addToTail(ListNode pHead,int value){
        ListNode pNew=new ListNode(value);
        pNew.nextNode=null;
        if (pHead == null) {
            pHead=pNew;
        }
        else{
            ListNode pNode=pHead;
            while(pNode.nextNode!=null){
                pNode=pNode.nextNode;
            }
            pNode.nextNode=pNew;
        }
    }
}

第一个参数pHead是指向指针的指针。当我们往一个空链表中插入一个节点时,新插入的节点就是链表的头指针

由于此时会改动头指针,因此必须把pHead参数设为指向指针的指针,否则除了这个函数pHead仍然是一个空指针

 

链表中的内存不是一次性分配的,无法保证链表的内存连续,因此如果想在链表中找到它的第i个节点,那么我们只能从头节点开始,沿着指向下一个结点的指针遍历链表,他的时间效率为O(n)。而在数组中,我们可以根据下标在O(1)时间内找到第i个元素

 

在链表中找到第一个含有某值的节点并删除该节点的代码

public static void removeNode(ListNode pHead ,int value){
    //如果头节点是空的
    if(pHead==null||pHead==null){
        return;
    }
    //初始化删除节点
    ListNode pToBeDeleted=null;
    //遍历链表如果链表头节点值确定
    if(pHead.value==value){
        //删除节点变为当前节点
        pToBeDeleted=pHead;
        //头节点下移
        pHead=pHead.nextNode;
    }
    //如果链表节点值不与目标值相同
    else{
        ListNode pNode=pHead;
        //当头节点不为空
        while(pNode.nextNode!=null&&pNode.nextNode.value!=value){
            //移动到下一节点
            pNode=pNode.nextNode;
        }
        //如果下一节点值与目标值相同
        if(pNode.nextNode!=null&&pNode.nextNode.value==value){
            pToBeDeleted=pNode.nextNode;
            //把目标节点断开,上一节点指向目标节点的下一节点
            pNode.nextNode=pNode.nextNode.nextNode;
        }
    }
    //消除目标节点
    if(pToBeDeleted!=null){
        pToBeDeleted=null;
    }
}

 

面试题6.从头到尾打印链表

题目:输入一个链表的头节点,从尾到头反过来打印出每个节点值

 

遍历链表

后进先出->用栈

public class printReversedList {
    public static void printReversedList(ListNode pHead){
        Stack<ListNode> nodes = new Stack<>();
        ListNode pNode=pHead;
        //遍历链表把链表中的值全部顺序放入栈中
        while(pNode!=null){
            nodes.push(pNode);
            pNode=pNode.nextNode;
        }
        //当栈中有值顺序弹出
        while(!nodes.empty()){
            pNode=nodes.peek();
            System.out.print(pNode.value+" ");
            nodes.pop();
        }
    }
    public static void main(String[] args){
        ListNode officers = new ListNode(1);
        ListNode pHead=officers;
        for(int i=2;i<=5;i++){
            officers.nextNode = new ListNode(i);
            officers=officers.nextNode;
        }
        printReversedList(pHead);
    }
}

上述很简洁,但是链表很长的时候调用很深,可能导致函数调用栈溢出。

posted @ 2021-02-21 11:30  Heinrich♣  阅读(91)  评论(0编辑  收藏  举报