【数据结构】线性表-循环链表(图解、c++、java)

文章目录

  • 什么是循环链表?
  • 循环链表的存储方式(图解)
  • 循环链表的基本操作
    • 1.初始化
    • 2.创建
    • 3.插入
    • 4.删除
    • 5.打印
    • 6.释放内存
  • 完整代码
  • 总结

GitHub同步更新(已分类):Data_Structure_And_Algorithm-Review

公众号:URLeisure 的复习仓库
公众号二维码见文末

以下是本篇文章正文内容,下面案例可供参考。


什么是循环链表?

  • 单链表中,只能向后,不能向前。

  • 如果从当前节点开始,无法访问该节点前面的节点,而最后一个节点的指针指向头节点,形成一个环,就可以从任何一个位置出发,访问所有的节点,这就是循环链表。

  • 循环链表和普通链表的区别:循环链表的最后一个节点的后继指针指向了头节点。

循环链表的存储方式(图解)

  • 单向循环链表的最后一个节点的next域不能为空,而是指向头节点。
    【数据结构】线性表-循环链表(图解、c++、java)_第1张图片
  • 双向循环链表除了让最后一个节点的后继指针指向第一个节点外,还要让头节点的前驱指向最后一个节点。
    【数据结构】线性表-循环链表(图解、c++、java)_第2张图片

循环链表的基本操作

  • 因为循环链表的取值、查找代码没有改变,这里就不再写了。

  • 首先定义一个结构体(内部类),包含数据域与指针域。

c++代码如下(示例):

typedef struct LNode{
    int data;
    LNode *next;
}*LinkList;

java代码如下(示例):

public static class LNode{
 	int date;
	LNode next;
}

1.初始化

  • 循环链表的初始化是指构建一个空表。先创建一个头节点,不存储数据,然后令其指针域指向自己。

    • 单向循环链表

【数据结构】线性表-循环链表(图解、c++、java)_第3张图片

  • 双向循环链表
    【数据结构】线性表-循环链表(图解、c++、java)_第4张图片

c++代码如下(示例):

bool Init(LinkList &L){
    L = new LNode;
    if(!L){
        return false;
    }
    L->next = L;
    L->data = 0;
    return true;
}

java代码如下(示例):

public static LNode init(LNode L){
	LNode lNode = new LNode();
    lNode.next = lNode;
    lNode.data = 0;
    return lNode;
}

2.创建

  • 循环链表的创建过程与单链表,双链表相同。

  • 我们以头插法为例。
    【数据结构】线性表-循环链表(图解、c++、java)_第5张图片

c++代码如下(示例):

void Create_H(LinkList &L,int n){
    LinkList s;
    while(n--){
        s = new LNode;
        cin >> s->date;
        //新节点next替换头节点next
        s->next = L->next;
        L->next = s;
    }
}

java代码如下(示例):

public static void create_H(LNode L,int n){
    LNode s;
    Scanner sc = new Scanner(System.in);
        while(n-- > 0){
        s = new LNode();
        s.data = sc.nextInt();
        s.next = L.next;
        L.next = s;
    }
}

3.插入

  • 插入也是相同的,只是在插入到最后一个节点时判断改一下。
    【数据结构】线性表-循环链表(图解、c++、java)_第6张图片

c++代码如下(示例):

bool Insert(LinkList &L,int i,int e){
    LinkList s, p = L;
    int j = 0;
    while(p->next != L && j < i - 1){
        p = p->next;
        j++;
    }
    if(j != i - 1){
        return false;
    }
    s = new LNode;
    s->data = e;
    s->next = p->next;
    p->next = s;
    return true;
}

java代码如下(示例):

public static boolean insert(LNode L,int i,int e){
    LNode s, ​p = L;
    int j = 0;
    while(p.next ​!= L && j < i - 1){
        p = p.next;
        j++;
    }
    if(j != i - 1){
        return false;
    }
    s = new LNode();
    s.data = e;
    s.next = p.next;
    p.next = s;
    return true;
}

4.删除

  • 删除也是相同的,只是在删除最后一个节点时判断改一下。

【数据结构】线性表-循环链表(图解、c++、java)_第7张图片

c++代码如下(示例):

bool Delete(LinkList &L,int i,int &e){
    LinkList q,p = L;
    int j = 0;
    while(p->next != L && j < i - 1){
        p = p->next;
        j++;
    }
    if(j != i-1){
        return false;
    }
    q = p->next;
    p->next = q->next;
    e = q->data;
    delete q;
    return true;
}

java代码如下(示例):

public static int delete(LNode L,int i){
    LNode q, ​p = L;
    int j = 0;
    while(p.next != L && j < i -1){
        p = p.next;
        j++;
    }
    if(j != j -1){
        return -1;
    }
    q = p.next;
    p.next = q.next;
    return q.data;
}

5.打印

  • 打印非常简单,直接上代码。

c++代码如下(示例):

void Print(LinkList L){
    LinkList p = L->next;
    while(p != L){
        cout<<p->data<<" ";
        p = p->next;
    }
    cout<<endl;
}

java代码如下(示例):

public static void print(LNode L){
    LNode p = L.next;
    while(p != L){
        System.out.print(p.data + " ");
        p = p.next;
    }
    System.out.println();
}

6.释放内存

  • c++需要手动释放内存,而java不需要。

c++代码如下(示例):

void Destroy(LinkList &L){
    LinkList tmp;
    for(LinkList cur = L->next; cur != NULL; ){
        tmp = cur;
        cur = cur->next;
        delete tmp;
    }
    delete L;
}

完整代码

c++代码如下(示例):

​​#include<iostream>using namespace std;typedef struct LNode {
    int data;
    LNode *next;
} *LinkList;bool Init(LinkList &L) {
    L = new LNode;
    if (!L) {
        return false;
    }
    L->next = L;
    L->data = 0;
    return true;
}void Create_H(LinkList &L, int n) {
    LinkList s;
    while (n--) {
        s = new LNode;
        cin >> s->data;
        s->next = L->next;
        L->next = s;
    }
}bool Insert(LinkList &L, int i, int e) {
    LinkList s, p = L;
    int j = 0;
    while (p->next != L && j < i - 1) {
        p = p->next;
        j++;
    }
    if (j != i - 1) {
        return false;
    }
    s = new LNode;
    s->data = e;
    s->next = p->next;
    p->next = s;
    return true;
}bool Delete(LinkList &L, int i, int &e) {
    LinkList q, p = L;
    int j = 0;
    while (p->next != L && j < i - 1) {
        p = p->next;
        j++;
    }
    if (j != i - 1) {
        return false;
    }
    q = p->next;
    p->next = q->next;
    e = q->data;
    delete q;
    return true;
}void Print(LinkList L) {
    LinkList p = L->next;
    while (p != L) {
        cout << p->data << " ";
        p = p->next;
    }
    cout << endl;
}void Destroy(LinkList &L) {
    LinkList tmp;
    for (LinkList cur = L->next; cur != L;) {
        tmp = cur;
        cur = cur->next;
        delete tmp;
    }
    delete L;
}int main() {
    LinkList L;
    int choose = -1;
    int i, e, n;
    
    Init(L);//初始化
    
    cout << "输入元素个数:" << endl;
    cin >> n;
    cout << "依次输入要插入的元素" << endl;
    Create_H(L, n);
    cout << "双向链表表创建成功!" << endl;
​
    cout << "1 .插入\n";
    cout << "2 .删除\n";
    cout << "3 .输出\n";
    cout << "0 .退出\n";
    while (choose != 0) {
        cout << "请选择!" << endl;
        cin >> choose;
        switch (choose) {
            case 1:
                cout << "请输入要插入的位置和要插入的元素" << endl;
                cin >> i >> e;
                if (Insert(L, i, e)) {
                    cout << "插入成功!" << endl;
                } else {
                    cout << "插入失败!" << endl;
                }
                break;
            case 2:
                cout << "请输入要删除的位置i" << endl;
                cin >> i;
                if (Delete(L, i, e)) {
                    cout << "成功删除" << e << endl;
                } else {
                    cout << "删除失败!" << endl;
                }
                break;
            case 3:
                Print(L);
                break;
            case 0:
                cout << "成功退出" << endl;
                break;
        }
    }
    Destroy(L);
    return 0;
}

java代码如下(示例):

import java.util.Scanner;

public class A {
    public static class LNode {
        int data;
        LNode next;
    }

    public static LNode init(LNode L) {
        LNode lNode = new LNode();
        lNode.next = lNode;
        lNode.data = 0;
        return lNode;
    }

    public static void create_H(LNode L, int n) {
        LNode s;
        Scanner sc = new Scanner(System.in);
        while (n-- > 0) {
            s = new LNode();
            s.data = sc.nextInt();
            s.next = L.next;
            L.next = s;
        }
    }

    public static boolean insert(LNode L, int i, int e) {
        LNode s, p = L;
        int j = 0;
        while (p.next != L && j < i - 1) {
            p = p.next;
            j++;
        }
        if (j != i - 1) {
            return false;
        }
        s = new LNode();
        s.data = e;
        s.next = p.next;
        p.next = s;
        return true;
    }

    public static int delete(LNode L, int i) {
        LNode q, p = L;
        int j = 0;
        while (p.next != L && j < i - 1) {
            p = p.next;
            j++;
        }
        if (j != j - 1) {
            return -1;
        }
        q = p.next;
        p.next = q.next;
        return q.data;
    }

    public static void print(LNode L) {
        LNode p = L.next;
        while (p != L) {
            System.out.print(p.data + " ");
            p = p.next;
        }
        System.out.println();
    }

    public static void main(String[] args) {
        E e = new E();
        LNode L = new LNode();
        int n, x, i;
        Scanner sc = new Scanner(System.in);
        L = init(L);
        
        System.out.println("输入元素个数:");
        n = sc.nextInt();
        System.out.println("依次输入要插入的元素");
        create_H(L, n);
        System.out.println("创建成功!");
        System.out.print("1.插入\n2.删除\n3.打印\n0.退出\n");
        int choose = -1;
        while (choose != 0) {
            System.out.println("请输入");
            choose = sc.nextInt();
            switch (choose) {
                case 1:
                    System.out.println("请输入要插入的位置和元素");
                    i = sc.nextInt();
                    x = sc.nextInt();
                    if (insert(L, i, x)) {
                        System.out.println("插入成功!");
                    } else
                        System.out.println("插入失败!");
                    break;
                case 2:
                    System.out.println("请输入要删除的位置");
                    i = sc.nextInt();
                    System.out.println("已删除" + delete(L, i));
                    break;
                case 3:
                    print(L);
                    break;
                case 0:
                    break;
            }
        }
    }
}

总结

优点:

  1. 链表是动态存储,不需要预先分配最大空间
  2. 插入删除不需要移动元素

缺点:

  • 每次动态分配一个节点时,节点的地址都是不连续的,需要有指针域记录下一个节点的地址,指针域需要占用一个 int 的空间,因此存储密度低(数据所占空间 ÷ 节点所占总空间)

双向循环链表和单向循环链表的改法基本相同,所以只发了单向循环链表的代码。

关注公众号,感受不同的阅读体验

请添加图片描述

下期预告:栈链

你可能感兴趣的:(链表,数据结构,java,c++,图解法)