链表

链表

  • 链表是以节点的方式存储
  • 每个节点包含data域和next域,next域:指向下一个节点
  • 链表的存储不一定是连续的存储
  • 链表
    • 带头节点链表
    • 不带头节点的链表

单链表示意图:
链表_第1张图片

添加节点到单链表(不排序)

添加(创建)

  1. 创建一个head头节点,作用就是表示链表头
  2. 后面每个节点就加入到链表的最后

遍历

  1. 通过一个辅助遍历,帮助遍历整个单链表
/**
 * 添加节点到单链表
 * 不考虑编号顺序
 * 1.找到当前链表的最后节点
 * 2.将最后这个节点的next指向新的节点
 * @param heroNode
 */
public void add(HeroNode heroNode){
     

    //创建辅助遍历节点temp
    HeroNode temp = head;

    //循环遍历找到最后一个节点
    while (true){
     
        if(temp.getNextNode() == null){
     
            break;
        }
        temp = temp.getNextNode();
    }

    //将最后节点的next 指向新的节点
    temp.setNextNode(heroNode);

}
//获取打印链表
public void list(){
     
        //链表为空,直接返回
        if(head.getNextNode() == null){
     
            return;
        }
        //创建辅助遍历节点temp
        HeroNode temp = head;
        while (true){
     
            System.out.println(temp.toString());
            if(temp.getNextNode() == null){
     
                break;
            }
            temp = temp.getNextNode();
        }
}

添加节点到单链表(排序)

添加

  1. 找到新添加的节点的位置,通过辅助变量实现 temp,用遍历搞定
  2. 新节点.next=temp.next
  3. 将temp.next = 新节点
public void addBySort(HeroNode heroNode){
     

    HeroNode temp = head;
    boolean flag = false; //判断添加的标志是否存在

    while (true){
     

        if(temp.getNextNode() == null){
     //头节点直接返回
            break;
        }
        if(temp.getNextNode().getNo() > heroNode.getNo()){
     
            //插入位置
            break;
        }
        if (temp.getNextNode().getNo() == heroNode.getNo()){
     
            flag = true;//已经插入直接返回
            break;
        }
        temp = temp.getNextNode();
    }
    if(!flag){
     
        heroNode.setNextNode(temp.getNextNode());
        temp.setNextNode(heroNode);
    }else {
     
        throw new RuntimeException("add node exist!");
    }

}

修改节点

public void updateByNo(HeroNode heroNode){
     
    if(head.getNextNode() == null){
     
        System.out.println("linkedlist is empty !");
    }
    HeroNode temp = head;
    boolean flag = false;
    while (true){
     
        if(temp.getNo() == heroNode.getNo()){
     
            flag = true;
            break;
        }
        temp = temp.getNextNode();
    }
    if(flag){
     
        temp.setName(heroNode.getName());
        temp.setNickName(heroNode.getNickName());
    }

}

删除节点

  • 找到要删除节点的前一个节点temp
  • temp.next = temp.next.next;
  • 被删除的节点,将不会有其他引用,会被GC回收
public void delete(HeroNode heroNode){
     
    if (head.getNextNode() == null){
     
        System.out.println("linkedlist is empty !");
        return;
    }
    HeroNode temp = head;
    boolean flag = false;
    while (true){
     
        if(temp.getNextNode().getNo() == heroNode.getNo()){
     
            flag = true;
            break;
        }
        temp = temp.getNextNode();
    }
    if(flag){
     
        temp.setNextNode(temp.getNextNode().getNextNode());
    }
}

练习

  • 获取链表的节点个数
public static int getNum(SingleLinkedList singleLinkedList){
     
    int sum = 0;
    HeroNode temp =  singleLinkedList.head;

    while (true){
     
        if(temp.getNextNode() == null){
     
            break;
        }
        sum++;
        temp = temp.getNextNode();
    }
    return sum;
}
  • 查找链表中倒数第k个节点

思路:

  1. 将链表从头到尾遍历,得到链表的总长度length
  2. 得到length后,我们从链表的第一个开始遍历(length-k)个,得到节点
public HeroNode lastTop(SingleLinkedList singleLinkedList,int k){
     

    int length = getNum(singleLinkedList);
    HeroNode temp =  singleLinkedList.head;
    for (int i = 0; i < length-k+1; i++) {
     
        temp = temp.getNextNode();
    }
    return  temp;
}
  • 将链表翻转

思路:

  1. 先定义一个节点reverseHead
  2. 从头到尾遍历链表,每遍历一个节点,就将其取出,并放在新的链表reverseHead的后端
  3. 原来的链表的head.next = reverseHead.next
public void reverse(){
     
    if(head.getNextNode() == null || head.getNextNode().getNextNode() == null){
     
        System.out.println("链表元素为0或只有一个元素");
        return;
    }
    HeroNode reverseHead = new HeroNode(0,"","");
    //定义一个辅助指针变量,帮助我们遍历原来的链表
    HeroNode cur = head.getNextNode();
    HeroNode next = null; //指向当前节点[cur]的下一个节点
    while (cur != null){
     
        next = cur.getNextNode(); //保存当前节点的下一个节点
        cur.setNextNode(reverseHead.getNextNode());//将cur的下一个节点指向新的链表的最前端
        reverseHead.setNextNode(cur);
        cur = next;//让cur后移
    }
    //将head.next指向reverseHead.next实现单链表反转
    head.setNextNode(reverseHead.getNextNode());

}
  • 逆序打印单链表

思路:

  1. 先将链表反转,然后再遍历,会破坏原来的链表结构,不建议使用
  2. 利用栈,将各个节点压入到栈中,利用栈先进后出的特点实现逆序打印
public void reversePrint(){
     
    if (head.getNextNode() == null){
     
        System.out.println("链表元素为0");
        return;
    }
    Stack<HeroNode> stack = new Stack<>();//利用栈实现
    HeroNode temp = head.getNextNode();
    while (true){
     
        stack.add(temp);//入栈
        if(temp.getNextNode()==null){
     
            break;
        }
        temp = temp.getNextNode();
    }
    while (stack.size()>0){
     
        System.out.println(stack.pop().toString());//弹出并打印
    }
}
  • 合并两个有序单链表,合并之后的链表依然有序

你可能感兴趣的:(数据结构,java,数据结构)