循环链表就是把头尾接起来了。 有循环单链表和循环双链表,实现原理基本一致。

因此就用循环双链表举例吧。

创建节点类和初始化链表

public class CycleLinkedList {

    public class Data{
        int num;
        Data last = null;
        Data next = null;
        public Data(int num){
            this.num = num;
        }
    }

    Data head = new Data(0);
    Data tail = new Data(0);
    public CycleLinkedList(){
        head.next = tail;
        tail.last = head;
    }
}

插入数据,注意最后一个节点指向第一个节点,第一个节点指向最后一个节点,这样才能形成一个循环。

//  头插法
public void insertP(int num){
    Data data = new Data(num);

    data.next = head.next;
    head.next.last = data;
    head.next = data;

    // 这里,插入节点的上一位不再指向头节点,而是指向最后的数据
    // 同时把最后一个数据节点的下一位指向自己,形成一个循环
    data.last = tail.last;
    tail.last.next = data;
}

//  尾插法
public void insertE(int num){
    Data data = new Data(num);

    data.last = tail.last;
    tail.last.next = data;
    tail.last = data;

    // 这里和上面一样的道理
    data.next = head.next;
    head.next.last = data;
}



//  查找
public void find(int num){
    // 链表判空
    if(head.next == tail){
        return;
    }
    Data cur = head.next;
    int i = 0;
    do{
        if(cur.num == num){
            System.out.println("找到数字 " + num + ", 位于链表的第 " + i + " 个");
        }
        i++;
        cur = cur.next;
    } while(cur != head.next);
    // 指针又回到了第一个节点,跳出循环
}

根据索引删除和替换,那怎么根据数值删除呢?结合一下查找函数和删除函数不久可以了嘛,之前几篇也有相关代码。

//  根据索引删除数据 (从0计数)
public void remove(int index){
    if(head.next == tail){
        return;
    }
    Data cur = head.next;
    for(int i = 0; i < index+1; i++){
        if(i == index){
            cur.last.next = cur.next;
            cur.next.last = cur.last;

            if(cur == head.next){ // 如果是第一个节点
                head.next = head.next.next;
            } else if(cur == tail.last){ // 如果是最后一个节点
                tail.last = tail.last.last;
            }
            break;
        }
        cur = cur.next;
        if(cur == head.next){// 指针回到了开头
            System.out.println("索引不存在");
            break;
        }
    }
}

//  根据索引替换数据 (从0计数)
public void replace(int index, int num){
    if(head.next == tail){
        return;
    }
    Data cur = head.next;
    for(int i = 0; i < index+1; i++){
        if(i == index){
            cur.num = num;
            break;
        }
        cur = cur.next;
        if(cur == head.next){// 指针回到了开头
            System.out.println("索引不存在");
            break;
        }
    }
}

补充一个之前没提到过的——加塞数据

//  加塞数据
public void add(int index, int num){
    if(head.next == tail){
        return;
    }

    // 在0处插入,调用头插函数
    if(index == 0){
        insertP(num);
        return;
    }
    // 中间插入的情况
    Data cur = head.next;
    for(int i = 0; i < index+1; i++){
        if(i == index){
            Data data = new Data(num);
            data.next = cur;
            data.last = cur.last;
            cur.last.next = data;
            cur.last = data;
            break;
        }

        cur = cur.next;
        if(cur == head.next){
            // 在回到头部时,i 为总元素个数
            // 如果index等于i+1,则调用尾插法
            if(index == i+1){
                insertE(num);
                break;
            }
            break;
        }
    }
}

显示和反向显示,双链表就是这么方便。

反向显示就是顺序倒过来了。

//  显示
public void display(){
    if(head.next == tail){
        return;
    }
    Data cur = head.next;
    do{
        System.out.print(cur.num + "   ");
        cur = cur.next;
    } while( cur != head.next);

    System.out.println("\n");
}

//  反向显示 和正向道理是一样的
public void antiDisplay(){
    if(head.next == tail){
        return;
    }
    Data cur = tail.last;
    do{
        System.out.print(cur.num + "   ");
        cur = cur.last;
    } while(cur != tail.last);
    System.out.println("\n");
}

测试测试~

public static void main(String[] args){
    CycleLinkedList cll = new CycleLinkedList();

    System.out.println("尾插法插入 1 5 3 5 5 6");
    cll.insertE(1);
    cll.insertE(5);
    cll.insertE(3);
    cll.insertE(5);
    cll.insertE(5);
    cll.insertE(6);
    cll.display();

    System.out.println("反向显示");
    cll.antiDisplay();

    System.out.println("查找 5");
    cll.find(5);

    System.out.println("\n把8插入到第0位,把2插入到第5位,把7插入到第100位");
    cll.add(0, 8);
    cll.add(5, 2);
    cll.add(100, 7);
    cll.display();

    System.out.println("删除第5个元素和第0个元素");
    cll.remove(5);
    cll.remove(0);
    cll.display();

    System.out.println("反向显示");
    cll.antiDisplay();          
}

输出结果

尾插法插入 1 5 3 5 5 6
1   5   3   5   5   6   

反向显示
6   5   5   3   5   1   

查找 5
找到数字 5, 位于链表的第 1 个
找到数字 5, 位于链表的第 3 个
找到数字 5, 位于链表的第 4 个

把8插入到第0位,把2插入到第5位,把7插入到第100位
8   1   5   3   5   2   5   6   

删除第5个元素和第0个元素
1   5   3   5   5   6   

反向显示
6   5   5   3   5   1   

完整代码

public class CycleLinkedList {

    public class Data{
        int num;
        Data last = null;
        Data next = null;
        public Data(int num){
            this.num = num;
        }
    }

    Data head = new Data(0);
    Data tail = new Data(0);
    public CycleLinkedList(){
        head.next = tail;
        tail.last = head;
    }

    //  头插法
    public void insertP(int num){
        Data data = new Data(num);

        data.next = head.next;
        head.next.last = data;
        head.next = data;

        // 这里,插入节点的上一位不再指向头节点,而是指向最后的数据
        // 同时把最后一个数据节点的下一位指向自己,形成一个循环
        data.last = tail.last;
        tail.last.next = data;
    }

    //  尾插法
    public void insertE(int num){
        Data data = new Data(num);

        data.last = tail.last;
        tail.last.next = data;
        tail.last = data;

        // 这里和上面一样的道理
        data.next = head.next;
        head.next.last = data;
    }

    //  根据索引删除数据 (从0计数)
    public void remove(int index){
        if(head.next == tail){
            return;
        }
        Data cur = head.next;
        for(int i = 0; i < index+1; i++){
            if(i == index){
                cur.last.next = cur.next;
                cur.next.last = cur.last;

                if(cur == head.next){ // 如果是第一个节点
                    head.next = head.next.next;
                } else if(cur == tail.last){ // 如果是最后一个节点
                    tail.last = tail.last.last;
                }
                break;
            }
            cur = cur.next;
            if(cur == head.next){// 指针回到了开头
                System.out.println("索引不存在");
                break;
            }
        }
    }

    //  根据索引替换数据 (从0计数)
    public void replace(int index, int num){
        if(head.next == tail){
            return;
        }
        Data cur = head.next;
        for(int i = 0; i < index+1; i++){
            if(i == index){
                cur.num = num;
                break;
            }
            cur = cur.next;
            if(cur == head.next){// 指针回到了开头
                System.out.println("索引不存在");
                break;
            }
        }
    }

    //  加塞数据
    public void add(int index, int num){
        if(head.next == tail){
            return;
        }

        // 在0处插入,调用头插函数
        if(index == 0){
            insertP(num);
            return;
        }
        // 中间插入的情况
        Data cur = head.next;
        for(int i = 0; i < index+1; i++){
            if(i == index){
                Data data = new Data(num);
                data.next = cur;
                data.last = cur.last;
                cur.last.next = data;
                cur.last = data;
                break;
            }

            cur = cur.next;
            if(cur == head.next){
                // 在回到头部时,i 为总元素个数
                // 如果index等于i+1,则调用尾插法
                if(index == i+1){
                    insertE(num);
                    break;
                }
                break;
            }
        }
    }

    //  查找
    public void find(int num){
        // 链表判空
        if(head.next == tail){
            return;
        }
        Data cur = head.next;
        int i = 0;
        do{
            if(cur.num == num){
                System.out.println("找到数字 " + num + ", 位于链表的第 " + i + " 个");
            }
            i++;
            cur = cur.next;
        } while(cur != head.next);
        // 指针又回到了第一个节点,跳出循环
    }


    //  显示
    public void display(){
        if(head.next == tail){
            return;
        }
        Data cur = head.next;
        do{
            System.out.print(cur.num + "   ");
            cur = cur.next;
        } while( cur != head.next);

        System.out.println("\n");
    }

    //  反向显示 和正向道理是一样的
    public void antiDisplay(){
        if(head.next == tail){
            return;
        }
        Data cur = tail.last;
        do{
            System.out.print(cur.num + "   ");
            cur = cur.last;
        } while(cur != tail.last);
        System.out.println("\n");
    }

    public static void main(String[] args){
        CycleLinkedList cll = new CycleLinkedList();

        System.out.println("尾插法插入 1 5 3 5 5 6");
        cll.insertE(1);
        cll.insertE(5);
        cll.insertE(3);
        cll.insertE(5);
        cll.insertE(5);
        cll.insertE(6);
        cll.display();

        System.out.println("反向显示");
        cll.antiDisplay();

        System.out.println("查找 5");
        cll.find(5);

        System.out.println("\n把8插入到第0位,把2插入到第5位,把7插入到第100位");
        cll.add(0, 8);
        cll.add(5, 2);
        cll.add(100, 7);
        cll.display();

        System.out.println("删除第5个元素和第0个元素");
        cll.remove(5);
        cll.remove(0);
        cll.display();

        System.out.println("反向显示");
        cll.antiDisplay();          
    }
}

数据结构:循环链表

Apr.09 2018
CATT-L
我们把链表的头尾接起来了
关于页面
返回