单向.双向.环形链表的基本操作--风之java

链表

  • 单项链表
    • 判断链表是否为空
    • 增加
    • 删除
    • 查找
    • 更改
    • 插入
    • 遍历
    • 反转链表
    • 整体代码实现
    • 如何操作链表:
  • 双向链表
    • 判断链表是否为空
    • 增加
    • 删除
    • 查找
    • 更改
    • 插入
    • 遍历双向链表
    • 整体代码实现
    • 操作双向链表
  • 环形链表
    • 利用环形链表约瑟夫问题的解决

单项链表

逻辑结构图:
在这里插入图片描述
先创建一个节点类:
为了简化代码链表中的真实数据均整形data表示,并用Num(Num从1开始)记录对应的下标。

public class Node {
    int data;//链表中的真实数据
    int Num;//对应下标
    Node next;//指针

    public Node(){}

    public Node(int data){
        this.data=data;
        next=null;
    }

    public Node(int data,int Num){
        this.data=data;
        this.Num=Num;
    }

然后创建一个单向链表类

public class DemoNdeList {
    private Node first;
    private Node last;
    private int total;
    public NodeList(){}
 public boolean isEmpty(){}//判断链表是否为空
 public void add(Node newNode){}//增加元素
 public void delete(Node delNode){}//删除元素
 public Node findElem(Node findNode){}//查找元素
 public void revise(Node reNode){}//更改元素
  public void insertElem(Node newNode){}//往中间插入元素
   public void ergod(){}//遍历元素
   public void reverseElem(){}//反转链表
   
}

接下来一一实现上述方法:

判断链表是否为空

 public boolean isEmpty(){
        return first==null;
    }

增加

头插法

public void add(Node newNode){
        if(isEmpty()){
            first=newNode;
            last=newNode;
        }else{
            last.next=newNode;
            last=newNode;
        }
        newNode.Num=++total;
    }

删除

public void delete(Node delNode){
        if(isEmpty()){
            System.out.println("链表为空,无删除选项");
        }
        else if(delNode.Num==first.Num){
            first=first.next;
            Node newptr=first;
            while(newptr!=null){
                newptr.Num--;
                newptr=newptr.next;
            }
            total--;
        }
        else if(delNode.Num==last.Num){
            Node cur=first;
            while(cur.next.Num!=last.Num)
                cur=cur.next;
            cur.next=null;
            last=cur;
            total--;
        }
        else {
            Node cur = first;
            Node ptr = first;
            while (cur != null && cur.Num != delNode.Num) {//找到被修改元素
                ptr = cur;
                cur = cur.next;
            }
            if (cur != null) {
                ptr.next = cur.next;
                Node newptr = cur.next;
                while (newptr != null) {
                    newptr.Num--;
                    newptr = newptr.next;
                }
                total--;
            } else {
                System.out.println("查无此元素");
            }
        }
    }

查找

public Node findElem(Node findNode){
        if(isEmpty()){
            System.out.println("链表为空,无法查找");
            return null;
        }
        Node cur=first;
        while(cur!=null&&cur.data!=findNode.data)
            cur=cur.next;

        return cur;
    }

更改

    public void revise(Node reNode){
        if(isEmpty()){
            System.out.println("链表为空,无法查找");
            return;
        }
        Node cur=first;
        while(cur!=null&&cur.Num!=reNode.Num)
            cur=cur.next;
        if(cur!=null){
            cur.data=reNode.data;
        }else{
            System.out.println("查无此元素");
        }

插入

注意这里的插入方法只涉及往中间插,不涉及头插与尾插。

    public void insertElem(Node newNode){
        if(isEmpty()){
         first=newNode;
         last=newNode;
         return;
        }
        Node cur=first;
        Node ptr=first;
        while(cur!=null&&cur.Num!= newNode.Num) {//找到插入位置
            ptr=cur;
            cur = cur.next;
        }
        if(cur!=null){
            ptr.next=newNode;
            newNode.next=cur;
            while(cur!=null){
                cur.Num++;
                cur=cur.next;
            }
            total++;
        }
    }

遍历

    public void ergod(){
        if(isEmpty()){
            System.out.println("链表为空,无法遍历");
            return;
        }
        Node cur=first;
        while(cur!=null){
            System.out.println(cur.Num+"\t"+cur.data);
            cur=cur.next;
        }
    }

反转链表

先用tmp记录cur.next,然后将cur指向的下一个结点的指针(cur.next)指向上一个结点(bef),如此反复,直到最后一个节点即可。

 public void reverseElem(){
        Node cur=first;
        Node bef=null;
        while(cur!=null){
            Node tmp=cur.next;
            cur.next=bef;
            bef=cur;
            cur=tmp;

        }
        first=bef;
    }

整体代码实现

public class NodeList {
    private Node first;
    private Node last;
    private int total;
    public NodeList(){}
    //判断是否为空
    public boolean isEmpty(){
        return first==null;
    }
    //增加元素
    public void add(Node newNode){
        if(isEmpty()){
            first=newNode;
            last=newNode;
        }else{
            last.next=newNode;
            last=newNode;
        }
        newNode.Num=++total;
    }
    //删除元素
    public void delete(Node delNode){
        if(isEmpty()){
            System.out.println("链表为空,无删除选项");
        }
        else if(delNode.Num==first.Num){
            first=first.next;
            Node newptr=first;
            while(newptr!=null){
                newptr.Num--;
                newptr=newptr.next;
            }
            total--;
        }
        else if(delNode.Num==last.Num){
            Node cur=first;
            while(cur.next.Num!=last.Num)
                cur=cur.next;
            cur.next=null;
            last=cur;
            total--;
        }
        else {
            Node cur = first;
            Node ptr = first;
            while (cur != null && cur.Num != delNode.Num) {//找到被修改元素
                ptr = cur;
                cur = cur.next;
            }
            if (cur != null) {
                ptr.next = cur.next;
                Node newptr = cur.next;
                while (newptr != null) {
                    newptr.Num--;
                    newptr = newptr.next;
                }
                total--;
            } else {
                System.out.println("查无此元素");
            }
        }
    }
    //查找元素
    public Node findElem(Node findNode){
        if(isEmpty()){
            System.out.println("链表为空,无法查找");
            return null;
        }
        Node cur=first;
        while(cur!=null&&cur.data!=findNode.data)
            cur=cur.next;

        return cur;
    }
    //更改元素
    public void revise(Node reNode){
        if(isEmpty()){
            System.out.println("链表为空,无法查找");
            return;
        }
        Node cur=first;
        while(cur!=null&&cur.Num!=reNode.Num)
            cur=cur.next;
        if(cur!=null){
            cur.data=reNode.data;
        }else{
            System.out.println("查无此元素");
        }
    }
    //往中间插入元素插入元素
    public void insertElem(Node newNode){
        if(isEmpty()){
         first=newNode;
         last=newNode;
         return;
        }
        Node cur=first;
        Node ptr=first;
        while(cur!=null&&cur.Num!= newNode.Num) {//找到插入位置
            ptr=cur;
            cur = cur.next;
        }
        if(cur!=null){
            ptr.next=newNode;
            newNode.next=cur;
            while(cur!=null){
                cur.Num++;
                cur=cur.next;
            }
            total++;
        }
    }
    //遍历链表
    public void ergod(){
        if(isEmpty()){
            System.out.println("链表为空,无法遍历");
            return;
        }
        Node cur=first;
        while(cur!=null){
            System.out.println(cur.Num+"\t"+cur.data);
            cur=cur.next;
        }
    }
    //反转链表
    public void reverseElem(){
        Node cur=first;
        Node bef=null;
        while(cur!=null){
            Node tmp=cur.next;
            cur.next=bef;
            bef=cur;
            cur=tmp;

        }
        first=bef;
    }
}

如何操作链表:

import java.util.Scanner;
public class DemoNdeList {

    public static void menu(){
        System.out.println("          1.增加元素");
        System.out.println("          2.删除元素");
        System.out.println("          3.查找元素");
        System.out.println("          4.更改元素");
        System.out.println("          5.插入元素");
        System.out.println("          6.遍历链表");
        System.out.println("          7.反转链表");
        System.out.println("          8.退出");
    }

    public static void main(String[] args){
        NodeList L=new NodeList();

        Scanner sc=new Scanner(System.in);
        boolean flag=true;
        while(flag){
            menu();
            int key=sc.nextInt();
            switch(key){

                case 1:
                    System.out.println("请输入数字:");
                    int n1=sc.nextInt();
                    Node w1=new Node(n1);
                    L.add(w1);
                    break;
                case 2:
                    System.out.println("请输入删除元素序列号:");
                    int n2=sc.nextInt();
                    Node w2=new Node();
                    w2.Num=n2;
                    L.delete(w2);
                    break;
                case 3:
                    System.out.println("请输入查找元素数据:");
                    int n3=sc.nextInt();
                    Node w3=new Node(n3);
                    if(L.findElem(w3)!=null){
                        System.out.println("找到此元素,序列为:"+L.findElem(w3).Num);
                    }
                    break;
                case 4:
                    System.out.println("请输入更改元素序列号:");
                    int n4=sc.nextInt();
                    System.out.println("请输入更改数字");
                    int n44=sc.nextInt();
                    Node w4=new Node(n44,n4);
                    L.revise(w4);
                    break;
                case 5:
                    System.out.println("请输入要插入元素的数据");
                    int n5=sc.nextInt();
                    System.out.println("请输入将元素插入到的位置:");
                    int n55=sc.nextInt();
                    Node w5=new Node(n5,n55);
                    L.insertElem(w5);
                    break;
                case 6:
                    System.out.println("链表遍历如下:");
                    L.ergod();
                    break;
                case 7:
                    System.out.println("反转链表后,数据如下:");
                    L.reverseElem();
                    L.ergod();
                    break;
                case 8:
                    System.out.println("退出程序完毕");
                    flag=false;
                    break;
                default:
                    System.out.println("输入有误,请重新输入");
                    break;
            }
        }
    }
}

双向链表

双向链表逻辑结构:
在这里插入图片描述
和单链表一样先创建一个节点类:

public class Node {
    int data;//链表中真实数据
    int Num;//记录下标从一开始
    Node lnext;//记录前一个节点或左边结点
    Node rnext;//记录后一个结点或右结点

    public Node(){}
    public Node(int data){
        this.data=data;
        lnext=null;
        rnext=null;
    }
    public Node(int data,int Num){
        this.data=data;
        this.Num=Num;
        lnext=null;
        rnext=null;
    }
}

创建一个双向链表类:

public class DoubleLinkedList {
    private Node first;
    private Node last;
    private int total;
    public DoubleLinkedList(){}
 public boolean isEmpty(){}//判断链表是否为空
 public void add(Node newNode){}//增加元素
 public void delete(Node delNode){}//删除元素
 public Node findElem(Node findNode){}//查找元素
 public void revise(Node reNode){}//更改元素
  public void insertElem(Node newNode){}//往中间插入元素
   public void ergod(){}//遍历元素
   
}

判断链表是否为空

 public boolean isEmpty(){
        return first==null;
    }

增加

 public void add(Node newNode){
        if(isEmpty()){
            first=newNode;
            last=newNode;
        }else{
            newNode.lnext=last;
            last.rnext=newNode;
            last=newNode;
        }
        newNode.Num=++total;
    }

删除

public void delete(Node delNode){
        if(isEmpty()){
            System.out.println("链表为空,无删除选项");

        }
        else if(delNode.Num==first.Num){
            first=first.rnext;
            first.lnext=null;
            Node newptr=first;
            while(newptr!=null){
                newptr.Num--;
                newptr=newptr.rnext;
            }
            total--;
        }
        else if(delNode.Num==last.Num){
            Node tmp=last.lnext;
           last.lnext.rnext=null;
            last.lnext=null;
            last=tmp;
            total--;
        }
        else {
            Node cur = first;
            while (cur != null && cur.Num != delNode.Num) {//找到被修改元素
                cur = cur.rnext;
            }

            if (cur != null) {
                cur.lnext.rnext=cur.rnext;
                cur.rnext.lnext=cur.lnext;

                Node newptr = cur.rnext;
                while (newptr != null) {
                    newptr.Num--;
                    newptr = newptr.rnext;
                }
                total--;
            } else {
                System.out.println("查无此元素");
            }
        }
    }

查找

public Node findElem(Node findNode){
        if(isEmpty()){
            System.out.println("链表为空,无法查找");
            return null;
        }
        Node cur=first;
        while(cur!=null&&cur.Num!=findNode.Num)
            cur=cur.rnext;//从头往后查找

        return cur;
    }

更改

 public void revise(Node reNode){
        if(isEmpty()){
            System.out.println("链表为空,无法查找");
            return;
        }
        Node cur=first;
        while(cur!=null&&cur.Num!=reNode.Num)
            cur=cur.rnext;
        if(cur!=null){
            cur.data=reNode.data;
        }else{
            System.out.println("查无此元素");
        }
    }

插入

 public void insertElem(Node newNode){
        if(isEmpty()){
            first=newNode;
            last=newNode;
            return;
        }
        Node cur=first;
        while(cur!=null&&cur.Num!= newNode.Num) {//找到被修改元素
            cur = cur.rnext;
        }
        if(cur!=null){
            newNode.lnext=cur.lnext;
            cur.lnext.rnext=newNode;

            newNode.rnext=cur;
            cur.lnext=newNode;

            while(cur!=null){
                cur.Num++;
                cur=cur.rnext;
            }
            total++;
        }
    }

遍历双向链表

 public void ergod(){
        if(isEmpty()){
            System.out.println("链表为空,无法遍历");
            return;
        }
        Node cur=first;
        while(cur!=null){
            System.out.println(cur.Num+"\t"+cur.data);
            cur=cur.rnext;
        }
    }

整体代码实现

public class DoubleLinkedList {
    private Node first;
    private Node last;
    private int total;
    public DoubleLinkedList(){}
    //判断是否为空
    public boolean isEmpty(){
        return first==null;
    }
    //增加元素
    public void add(Node newNode){
        if(isEmpty()){
            first=newNode;
            last=newNode;
        }else{
            newNode.lnext=last;
            last.rnext=newNode;
            last=newNode;
        }
        newNode.Num=++total;
    }
    //删除元素
    public void delete(Node delNode){
        if(isEmpty()){
            System.out.println("链表为空,无删除选项");

        }
        else if(delNode.Num==first.Num){
            first=first.rnext;
            first.lnext=null;
            Node newptr=first;
            while(newptr!=null){
                newptr.Num--;
                newptr=newptr.rnext;
            }
            total--;
        }
        else if(delNode.Num==last.Num){
            Node tmp=last.lnext;
           last.lnext.rnext=null;
            last.lnext=null;
            last=tmp;
            total--;
        }
        else {
            Node cur = first;
            while (cur != null && cur.Num != delNode.Num) {//找到被修改元素
                cur = cur.rnext;
            }

            if (cur != null) {
                cur.lnext.rnext=cur.rnext;
                cur.rnext.lnext=cur.lnext;

                Node newptr = cur.rnext;
                while (newptr != null) {
                    newptr.Num--;
                    newptr = newptr.rnext;
                }
                total--;
            } else {
                System.out.println("查无此元素");
            }
        }
    }
    //查找元素
    public Node findElem(Node findNode){
        if(isEmpty()){
            System.out.println("链表为空,无法查找");
            return null;
        }
        Node cur=first;
        while(cur!=null&&cur.Num!=findNode.Num)
            cur=cur.rnext;//从头往友查找

        return cur;
    }
    //更改元素
    public void revise(Node reNode){
        if(isEmpty()){
            System.out.println("链表为空,无法查找");
            return;
        }
        Node cur=first;
        while(cur!=null&&cur.Num!=reNode.Num)
            cur=cur.rnext;
        if(cur!=null){
            cur.data=reNode.data;
        }else{
            System.out.println("查无此元素");
        }
    }
    //往中间插入元素插入元素
    public void insertElem(Node newNode){
        if(isEmpty()){
            first=newNode;
            last=newNode;
            return;
        }
        Node cur=first;
        while(cur!=null&&cur.Num!= newNode.Num) {//找到被修改元素
            cur = cur.rnext;
        }
        if(cur!=null){
            newNode.lnext=cur.lnext;
            cur.lnext.rnext=newNode;

            newNode.rnext=cur;
            cur.lnext=newNode;

            while(cur!=null){
                cur.Num++;
                cur=cur.rnext;
            }
            total++;
        }
    }
    //遍历链表
    public void ergod(){
        if(isEmpty()){
            System.out.println("链表为空,无法遍历");
            return;
        }
        Node cur=first;
        while(cur!=null){
            System.out.println(cur.Num+"\t"+cur.data);
            cur=cur.rnext;
        }
    }
}

操作双向链表

import java.util.Scanner;

public class DemoDoubleLinkedList {

 public static void menu(){
        System.out.println("          1.增加元素");
        System.out.println("          2.删除元素");
        System.out.println("          3.查找元素");
        System.out.println("          4.更改元素");
        System.out.println("          5.插入元素");
        System.out.println("          6.遍历链表");
        System.out.println("          7.退出");
    }

    public static void main(String[] args){
       DoubleLinkedList D=new DoubleLinkedList();

        Scanner sc=new Scanner(System.in);
        boolean flag=true;
        while(flag){
            menu();
            int key=sc.nextInt();
            switch(key){

                case 1:
                    System.out.println("请输入数字:");
                    int n1=sc.nextInt();
                    Node w1=new Node(n1);
                    D.add(w1);
                    break;
                case 2:
                    System.out.println("请输入删除元素序列号:");
                    int n2=sc.nextInt();
                    Node w2=new Node();
                    w2.Num=n2;
                    D.delete(w2);
                    break;
                case 3:
                    System.out.println("请输入查找元素数据:");
                    int n3=sc.nextInt();
                    Node w3=new Node(n3);
                    if(D.findElem(w3)!=null){
                        System.out.println("找到此元素,序列为:"+D.findElem(w3).Num);
                    }
                    break;
                case 4:
                    System.out.println("请输入更改元素序列号:");
                    int n4=sc.nextInt();
                    System.out.println("请输入更改数字");
                    int n44=sc.nextInt();
                    Node w4=new Node(n44,n4);
                    D.revise(w4);
                    break;
                case 5:
                    System.out.println("请输入要插入元素的数据");
                    int n5=sc.nextInt();
                    System.out.println("请输入将元素插入到的位置:");
                    int n55=sc.nextInt();
                    Node w5=new Node(n5,n55);
                    D.insertElem(w5);
                    break;
                case 6:
                    System.out.println("链表遍历如下:");
                    D.ergod();
                    break;
                case 7:
                    System.out.println("退出程序完毕");
                    flag=false;
                    break;
                default:
                    System.out.println("输入有误,请重新输入");
                    break;
            }
        }
    }
}

环形链表

环形链表和单项链表差不多,只不过是将首尾连接了起来形成一个环;
也是先创建一个结点:

public class Node {
        int data;
        Node next;
        public Node(){}

    public Node(int data){
            this.data=data;
            next=null;
    }
}

这里仅展示增加和遍历方法,其余方法可借鉴单向链表中的方法

public class CircleLink {
    private Node first;
    private Node last;
 public void add(Node newNode){
        if(first==null){
            first=newNode;
            last=newNode
           last.next=first;
        }else {
            last.next = newNode;
            newNode.next = first;
            last = newNode;
        }
    }
    //遍历环形链表
    public void show(){
        Node empty=first;
        if(empty==null){
            System.out.println("链表为空,无法遍历");
            return;
        }
        do{
            System.out.printf("this is %dth data\n",empty.data);
            empty=empty.next;
        }while(empty!=first);
    }
}

利用环形链表约瑟夫问题的解决

有n个人,编号为1~n,从第一个人开始报数,从1开始报,报到m的人会死掉,然后从第m+1个人开始,重复以上过程。在死了n-1个人后,问最后一个人的编号是?

public class CircleLink {
    private Node first;
    private Node last;

    public void add(int n){

        for(int i=1;i<=n;i++){
            Node newNode=new Node(i);
            if(first==null){
                first=newNode;
                last=newNode;
            }
            last.next=newNode;
            last=newNode;
        }
        last.next=first;
    }
    //解决约瑟夫问题
    public int solveJ(int n,int m){
        if(m == 1 || n < 2){
            System.out.println("输入参数有误");
            return 0;
        }
        add(n);
        int count=1;
        Node cur=first;
        Node ptr=null;

        while(cur.next!=cur){
            if(count==m){
                ptr.next=cur.next;
                cur=ptr.next;
                count=1;
            }else{
                ptr=cur;
                cur=cur.next;
                count++;
            }
        }
        return cur.data;
    }
    //遍历环形链表
    public void show(){
        Node empty=first;
        if(empty==null){
            System.out.println("this list is null");
            return;
        }
        do{
            System.out.printf("this is %dth data\n",empty.data);
            empty=empty.next;
        }while(empty!=first);
    }
}

你可能感兴趣的:(JAVA数据结构,链表)