剑指算法-单向循环链表

260 阅读4分钟

什么是单向循环链表

如图所示,单向循环链表是一个方向单一首尾相连的链表

循环链表的增删改查实现

链表的结构设计

typedef int DataType;
typedef struct Node{
    DataType data;
    struct Node *next;
}Node;
typedef Node *LinkList;

循环链表的创建

Status ListInit(LinkList *list){
    /**创建链表步骤
     1、判断当前链表是否为空,为空则创建链表,并将next指向自己
     2、如果链表不为空,则找到尾节点,然后将为节点的next指向b,b的next指向链表*list
     */
    int item;
    LinkList a = NULL;//尾节点
    LinkList b = NULL;//新节点
    printf("请输入数字,0为结束\n");
    while (1) {
        scanf("%d",&item);
        if (item == 0) break;
        //判断当前链表是否为空
        if (*list == NULL) {
            *list = malloc(sizeof(Node));
            (*list)->data = item;
            (*list)->next = *list;
        }else{
            //将当前的值插入到链表末尾,并将新值得next指向首节点
            for (a = *list; a->next != *list; a = a->next);
            b = malloc(sizeof(Node));
            b->data = item;
            b->next = *list;
            a->next = b;
        }
    }
    return SUCCESS;
}

上面的代码是利用循环的方式找到尾节点,这样就增加了时间的复杂度,也可以用一个临时变量来记录一下尾节点。

循环链表插入数据

Status ListInsert(LinkList *list){
    /**
     插入步骤:
     1、创建一个临时节点b,并判断是否创建成功
     2、判断插入位置是否是第一个。
        2.1、如果是第一个,就要找到最后一个尾节点a
        2.2、将尾节点a的next指向新节点
        2.3、将新节点b的next指向*list
     3、如果不是第一个
        3.1、循环遍历,找到插入位置的前一个节点a
        3.2、将新节点b的next指向a的next
        3.3、将前一个节点a的next指向新节点b
     */
    if (!list) return ERROR;
    int index,value,i;
    LinkList a,b;//a为插入位置的前一个节点,b为新插入的节点
    printf("请输入要插入的位置和值,中间用,隔开:\n");
    scanf("%d,%d",&index,&value);
    //判断插入位置是否是第一个
    b = malloc(sizeof(Node));
    if (!b) return ERROR;
    
    if (index == 1) {
        for (a = *list; a->next != *list; a = a->next);
        b->data = value;
        b->next = *list;
        a->next = b;
        *list = b;
    }else{
        if (!b) return ERROR;
        for (i = 1,a = *list;a->next != *list && i < index-1 ; a=a->next,i++);
        b->data = value;
        b->next = a->next;
        a->next = b;
    }
    
    return SUCCESS;
}

循环链表删除数据

Status ListDelete(LinkList *list){
    /**
     循环链表的删除步骤
     1、判断删除的位置是否是第一个
        1.1、如果是第一个,然后判断链表的next是否指向自己
        1.2、如果是,则将list赋值为NULL。
        1.3、如果不是,则找到最后一个尾节点,并且将链表的第一个节点给临时节点b,
            然后将链表的第一个节点赋值为b->next,在将尾节点的next指向新的头节点
        1.4、释放临时节点b
     2、如果不是第一个
        2.1、找到需要删除的位置的前一个节点a
        2.2、临时变量b赋值为a的next(b即为要删除的节点)
        2.3、a的next赋值b的next
        2.4、释放临时节点b
     */
    if (!list) return ERROR;
    int index,i;
    LinkList a,b;
    printf("请输入要删除的位置\n");
    scanf("%d",&index);
    if (index == 1) {
        if ((*list)->next == *list) {
            *list = NULL;
            return SUCCESS;
        }
        for (a = *list; a->next != *list; a = a->next);
        b = *list;
        *list = b->next;
        a->next = *list;
        free(b);
    }else{
        for (i = 1 ,a = *list; a->next != *list && i < index-1; a = a->next,i++);
        b = a->next;
        a->next = b->next;
        free(b);
    }
    return SUCCESS;
}

循环链表修改数据

Status ChangeValue(LinkList *list){
    /**
     循环链表的修改值的步骤
     1、先判断链表是否为空
     2、新建临时变量,并赋值链表的第一个节点
     3、找到要修改的值的节点a
     4、将新值赋给a的data
     */
    if (!*list) return ERROR;
    printf("请输入要修改的位置和值,用,隔开\n");
    int value,index,i;
    LinkList a = *list;
    scanf("%d,%d",&index,&value);
    for (i = 1; i<index && a->next != *list; i++,a = a->next);
    a->data = value;
    return SUCCESS;
};

循环链表查找数据

Status FindValue(LinkList list){
    /**
     循环链表查找的步骤
     1、先判断链表是否为空
     2、找到需要查找的节点
     3、输出节点的内容
     */
    if (list) return ERROR;
    printf("请输入要查找的值\n");
    int value,i = 1;
    scanf("%d",&value);
    
    while (value != list->data && list->next != list) {
        i++;
        list = list->next;
    }
    
    printf("查询的值为第%d位\n",i);
    
    return SUCCESS;
};