数据结构(4)线性表之单循环链表

数据结构(4)线性表之单循环链表

前言

所谓单循环链表,实际上就是在单链表的基础上,使最后一个结点的next指针再指向头结点,形成循环的效果。这样,从表中任何一个结点出发都可以找到其他结点的位置。

尾指针

顾名思义,尾指针是指向链表的最后一个结点。在单循环链表中,设立尾指针能使得一些操作简化,例如两个单循环链表的合并。

img_2

img_3

我们之前所写的管理结构,是既包括头指针又包括尾指针的,因此在实现某些操作时就很方便了。

单循环链表和单链表的实现思路、注意事项都是一样的,只是需要额外注意的是,在我们的管理结构中要注意保持last的next指针始终指向头结点,达到循环的效果。

附:单链表的实现思路及注意事项
数据结构(2.1)线性表之单链表的表示和实现
数据结构(2.2)线性表之单链表的具体实现

  • 链表为空

链表为空

  • 链表非空

链表非空

全部代码

单循环链表的各项操作与单链表并无差别,只是在判断链表结束的条件有差别,之前是判断next指针是否为空,现在需要判断是否为头结点。因此实现代码并没有巨大的改变,只是在一些判断条件上做出改变。

SCList.h

#ifndef SCList_h
#define SCList_h

#include <stdio.h>
#include <malloc.h>
#include <assert.h>

#define ElemType int

//结点的结构
typedef struct Node{
    ElemType data;
    struct Node *next;
}Node, *Pnode;

//链表的结构
typedef struct List{
    Pnode first;
    Pnode last;
    int size;
}List;

//初始化单循环链表
void InitSCList(List *list);

//1.尾部插入
void push_back(List *list,ElemType x);
//2.头部插入
void push_fount(List *list,ElemType x);
//3.展示
void show_list(List *list);
//4.尾部删除
void pop_back(List *list);
//5.头部删除
void pop_fount(List *list);
//6.按值插入(要求插入前的链表是有序的(此处为顺序
void insert_val(List *list,ElemType x);
//7.按值查找
Node* find(List *list,ElemType x);
//8.获取长度
int length(List *list);
//9.按值删除
void  delete_val(List *list,ElemType x);
//10.排序
void sort(List *list);
//11.逆置(前后转换
void resver(List *list);
//12.清除单链表 ->只清除数据,保留头结点
void clearList(List *list);
//13.摧毁 ->包括头结点在内一起摧毁
void destroy(List *list);

//生成一个结点
Node* getNode(ElemType x);
#endif /* SCList_h */

SCList.cpp

#include "SCList.h"

//初始化单循环链表
void InitSCList(List *list){
    Node *s = (Node *)malloc(sizeof(Node));
    assert(s != NULL);
    list->first = list->last = s;
    
    //让最后一个结点的next指向头部,形成循环
    list->last->next = list->first;
    list->size = 0;
}

//1.尾部插入
void push_back(List *list,ElemType x){
    Node *s = getNode(x);
    
    //将这个结点接到链表尾部
    list->last->next = s;
    
    //重新设置last指针的指向
    list->last = s;
    
    //让最后一个结点的next指向头部,形成循环
    list->last->next = list->first;
    list->size ++;
}


//2.头部插入
void push_fount(List *list,ElemType x){
    Node *s = getNode(x);
    
    s->next = list->first->next;
    list->first->next = s;
    
    //判断是否是第一个结点
    if (list->last == list->first) {
        //是,更改last指针的指向
        list->last = s;
    }
    
    list->size ++;
}

//3.展示
void show_list(List *list){
    Node *p = list->first->next;
    
    while (p != list->first) {
        printf("%4d",p->data);
        p = p->next;
    }
    printf("\n");
}


//4.尾部删除
void pop_back(List *list){
    if (list->size == 0) {
        printf("无可删除的结点!\n");
        return;
    }
    
    //寻找倒数第二个结点
    Node *p = list->first;
    while (p->next != list->last) {
        p = p->next;
    }
    
    //释放它后一个结点(即最后一个结点)
    free(list->last);
    //更改last指针的指向
    list->last = p;
    //让最后一个结点的next指向头部,形成循环
    list->last->next = list->first;
    list->size --;
}

//5.头部删除
void pop_fount(List *list){
    if (list->size == 0) {
        printf("无可删除的结点!\n");
        return;
    }
    
    Node *p = list->first->next;
    list->first->next = p->next;
    free(p);
    
    //判断是否是最后一个结点
    if(list->size == 1){
        //重新设置last的指向
        list->last = list->first;
    }
    
    list->size --;
}
//6.按值插入(要求插入前的链表是有序的(此处为顺序
void insert_val(List *list,ElemType x){
    Node *p = list->first;
    
    //寻找插入位置
    while (p->next != list->last && p->next->data < x) {
        p = p->next;
    }
    
    //到达了最后一个结点后,还需要与最后一个结点的值进行比较
    //判断是否比最后一个结点大
    if (p->next == list->last && p->next->data < x) {
        //是,直接进行尾部插入
        push_back(list, x);
    }else{
        //其他状况,直接在该位置进行插入
        Node *s = getNode(x);
        
        s->next = p->next;
        p->next = s;
        list->size ++;
    }
}
//7.按值查找
Node* find(List *list,ElemType x){
    if (list->size == 0) {
        return NULL;
    }
    
    //遍历整个链表
    Node *p = list->first->next;
    while (p != list->first && p->data != x) {
        p = p->next;
    }
    
    //判断是否回到头部
    if (p == list->first) {
        //是,说明链表中没有要找的数据
        return NULL;
    }else{
            return p;
    }
}
//8.获取长度
int length(List *list){
    return list->size;
}

//9.按值删除
void  delete_val(List *list,ElemType x){
    if (list->size == 0) {
        printf("链表为空,无法删除!\n");
        return;
    }
    
    Node *p = find(list, x);
    if (p == NULL) {
        printf("要删除的数据不存在!\n");
        return;
    }
    
    //判断是否是最后一个结点
    if (p == list->last) {
        //是,直接尾部删除
        pop_back(list);
    }else{
        //判断是否是倒数第二个结点
        if (p->next == list->last) {
            //是,需要修改last指针的指向
            list->last = p;
        }
        Node *s = p->next;
        p->data = s->data;
        p->next = s->next;
        free(s);
        list->size --;
    }
}

//10.排序
void sort(List *list){
    if (list->size <= 1) {
        return;
    }
    
    Node *s = list->first->next;
    Node *q = s->next;
    
    //将链表尾部断开
    list->last->next = NULL;
    //重新设置last指针
    list->last = s;
    //让链表再次循环
    list->last->next = list->first;
    
    while (q != NULL) {
        s = q;
        q = q->next;
        //进行按值插入
        insert_val(list, s->data);
        free(s);
        list->size --;
        
//        //寻找插入位置
//        Node *p = list->first;
//        while (p->next != list->last && p->next->data < s->data) {
//            p = p->next;
//        }
//
//        //判断是否是最后一个结点
//        if (p->next == list->last && p->next->data < s->data) {
//            //是,直接进行尾部插入
//            s->next = list->last->next;
//            list->last->next = s;
//            list->last = s;
//
//        }else{
//            s->next = p->next;
//            p->next = s;
//        }
        
    }
}

//11.逆置(前后转换
void resver(List *list){
    if (list->size <= 1) {
        return;
    }
    
    Node *s = list->first->next;
    Node *q = s->next;
    
    list->last->next = NULL;
    list->last = s;
    list->last->next = list->first;
    
    while (q != NULL) {
        s = q;
        q = q->next;
        //进行头部插入
        push_fount(list, s->data);
        free(s);
        list->size--;
        
//        //进行头部插入
//        s->next = list->first->next;
//        list->first->next = s;
    }
}

//12.清除单链表 ->只清除数据,保留头结点
void clearList(List *list){
    Node *p = list->first->next;
    while (p != list->first) {
        p = p->next;
        pop_fount(list);
    }
    
}
//13.摧毁 ->包括头结点在内一起摧毁
void destroy(List *list){
    clearList(list);
    free(list->first);
    list->first = list->last = NULL;
}

//生成一个结点
Node* getNode(ElemType x){
    Node *s = (Node *)malloc(sizeof(Node));
    assert(s != NULL);
    
    s->data = x;
    s->next = NULL;
    
    return s;
}

Main.cpp

#include "SCList.h"

int main(int argc, const char * argv[]) {
   
    List myList;
    InitSCList(&myList);
    
    //保存要输入的数据
    ElemType item;
    //保存要查找的地址
    Node *p = NULL;
    int select = 1;
    while (select) {
        printf("**************************************\n");
        printf("* [1] push_back      [2] push_front  *\n");
        printf("* [3] show_list      [4] pop_back    *\n");
        printf("* [5] pop_front      [6] insert_val  *\n");
        printf("* [7] find           [8] length      *\n");
        printf("* [9] delete_val     [10] sort       *\n");
        printf("* [11] resver        [12] clear      *\n");
        printf("* [13*] destroy       [0] quit_system*\n");
        printf("**************************************\n");
        printf("请选择:");
        scanf("%d",&select);
        if (select == 0) {
            break;
        }
        switch (select) {
            case 1:
                //尾部插入
                printf("请输入要插入的数据(-1结束):");
                scanf("%d",&item);
                while (item != -1) {
                    push_back(&myList, item);
                    scanf("%d",&item);
                }
                break;
            case 2:
                //头部插入
                printf("请输入要插入的数据(-1结束):");
                scanf("%d",&item);
                while (item != -1) {
                    push_fount(&myList, item);
                    scanf("%d",&item);
                }
                break;
            case 3:
                //展示单链表
                show_list(&myList);
                break;
            case 4:
                //尾部删除
                pop_back(&myList);
                break;
            case 5:
                //头部删除
                pop_fount(&myList);
                break;
            case 6:
                //按值插入
                printf("请输入要插入的数据:\n");
                scanf("%d",&item);
                insert_val(&myList, item);
                break;
            case 7:
                //按值查找
                printf("请输入要查找的值:\n");
                scanf("%d",&item);
                p = find(&myList, item);
                if (p == NULL) {
                    printf("要查找的数据不存在!\n");
                }else{
                    printf("地址为:%p\n",p);
                }
                break;
            case 8:
                //展示链表长度
                printf("链表的长度为:%d\n",length(&myList));
                break;
            case 9:
                //按值删除
                printf("请输入要删除的值:\n");
                scanf("%d",&item);
                delete_val(&myList, item);
                break;
            case 10:
                //排序
                sort(&myList);
                break;
            case 11:
                //逆置(前后转换
                resver(&myList);
                break;
            case 12:
                //清除
                clearList(&myList);
                break;
            case 13:
                destroy(&myList);
                break;
            default:
                printf("输入的命令有误,请重新插入\n");
                break;
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章