《数据结构》(C语言版)——循环链表

/* run this program using the console pauser or add your own getch, system("pause") or input loop */
// 用到的库文件
#include <stdio.h>  // printf();scanf()
#include <stdlib.h> // exit()
#include <malloc.h> // malloc()
#include <time.h>   // srand((unsigned)time(NULL));
// 函数结果状态代码
#define TRUE    1
#define FALSE   0
#define OK      1
#define ERROR   0
#define INFEASIBLE  -1
#define OVERFLOW    -2
// Status是函数的类型,其值是函数结果状态代码
typedef int Status;
// #define ElemType int  // 也可以用宏定义确定ElemType类型
typedef int ElemType;
// -----循环链表-----
typedef struct  LNode {
    ElemType data;                  // 数据域
    struct LNode *next;             // 指针域
} LNode, *CircleList;

// 操作结果:构造一个空的线性表L。
Status InitList_CL(CircleList &L) {
    if(L != NULL)
    {
        printf("线性表已存在!!!");
        return INFEASIBLE;          // 返回-1
    }
    L = (CircleList)malloc(sizeof(LNode));
    if(!L) {                        // 存储分配失败
        printf("初始化失败!!!");
        exit(OVERFLOW);             // exit(-2)程序异常退出
    }
    L->next = L;                    // 先建立一个带头结点的单链表,并使头结点指向本身(即头指针L)
    return OK;
}// InitList_CL

// 操作结果:销毁线性表L。
Status DestroyList_CL(CircleList &L) {
    if(L == NULL)
    {
        printf("线性表未初始化。");
        return INFEASIBLE;
    }

    CircleList p = L->next, ptmp;   // p指向线性表第一个结点
    while(p != L) {                 // p指向头结点时,循环停止
        ptmp = p->next;
        free(p);                    // 释放每个结点的指针域
        p = ptmp;
    }
    L->next = L;                    // 头结点指针域指向本身

    free(L);                        // 释放头结点
    L = NULL;

    return OK;
}// DestroyList_CL

// 操作结果:将L重置为空表。
Status ClearList_CL(CircleList &L) {
    if(!L)
    {
        printf("线性表未初始化。");
        return INFEASIBLE;
    }
    if(L->next == L)
    {
        printf("线性表本已空!!!");
        return INFEASIBLE;
    }
    CircleList p = L->next, ptmp;   // p指向线性表第一个结点
    while(p != L) {                 // p指向头结点时,循环停止
        ptmp = p->next;
        free(p);                    // 释放每个结点的指针域
        p = ptmp;
    }
    L->next = L;                    // 头结点指针域指向本身
    return OK;
}// ClearList_CL

// 操作结果:若L为空表,返回TRUE,否则返回FALSE
Status ListEmpty_CL(CircleList L) {
    if(!L)
    {
        printf("线性表未初始化。");
        return INFEASIBLE;          // 返回-1
    }
    else if(L->next == L)
    {
        printf("线性表为空。");
        return TRUE;                // 返回1
    }
    else
    {
        printf("线性表非空。");
        return FALSE;                // 返回0
    }
}// ListEmpty_CL

// 操作结果:返回L中数据元素个数。
int ListLength_CL(CircleList L) {
    if(!L)
    {
        printf("线性表未初始化。");
        return INFEASIBLE;          // 返回-1
    }
    int nElem = 0;
    CircleList p = L->next;         // p指向第一个结点
    while(p != L) {
        nElem ++;
        p = p->next;
    }
    return nElem;
}// ListLength

// 操作结果:用e返回L中第i个数据元素的值。1≤i≤ListLength(L) 。
Status GetElem_CL(CircleList L, int i, ElemType &e) {
    if(!L) {
        printf("线性表未初始化。");
        return INFEASIBLE;          // 返回-1
    }
    CircleList p = L->next;         // 初始化,p指向第一个结点(表空时,指向头结点)
    int j = 1;                      // j为计数器
    while ( (p->next != L) && j<i ) // 顺指针向后查找,直到p指向第i个元素或p指向头结点
    {
        p = p->next;
        ++j;
    }
    if ( p == L || j<i || i<1 )
    {
        return ERROR;               // 第i个元素不存在
    }
    e = p->data;                    // 取第i个元素
    return OK;
}// GetElem_CL 算法2.8更改

// 操作结果:返回L中第1个与e满足compare()(数据元素判定函数)的数据元素的位序,若这样的数据元素不存在,则返回值为0。
Status compare(ElemType listElem, ElemType e) {
    return listElem == e ? TRUE : FALSE;
}// Compare
int LocateElem_CL(CircleList L, ElemType e, Status (*pfn_compare)(ElemType, ElemType)) {
    if(!L) {
        printf("线性表未初始化。");
        return INFEASIBLE;          // 返回-1
    }
    int pos = 1;
    CircleList p = L->next;         // p指向链表第1个元素
    while(p!=L && !(*pfn_compare)(p->data, e)) {
        ++ pos;
        p = p->next;                // 指针后移p->next = L时,循环回到头结点
    }
    if(!L || pos>ListLength_CL(L))
    {
        return ERROR;               // 返回0
    }
    return pos;
}// LocateElem_CL

// 操作结果:若cur_e是L的数据元素,则用pre_e返回它的前驱,否则操作失败,pre_e无定义。
Status PriorElem_CL(CircleList L, ElemType cur_e, ElemType &pre_e) {
    int i = LocateElem_CL(L, cur_e, compare);
    // cur_e为第一个元素,其前驱为最后一个元素
    if(i==0 || i==1)
    {
        GetElem_CL(L, ListLength_CL(L), pre_e);
        return OK;
    }
    GetElem_CL(L, i-1, pre_e);
    return OK;
}// PriorElem_CL


// 操作结果:若cur_e是L的数据元素,则用next_e返回它的后继,否则操作失败,pre_e无定义。
Status NextElem_Sq(CircleList L, ElemType cur_e, ElemType &next_e) {
    int i = LocateElem_CL(L, cur_e, compare);
    // cur_e为最后一个元素,其后继为第一个元素
    if(i==0 || i==ListLength_CL(L))
    {
        GetElem_CL(L, 1, next_e);
        return OK;
    }
    GetElem_CL(L, i+1, next_e);
    return OK;
}// NextElem_Sq

// 操作结果:在L中第pos个位置之前插入新的元素e,L的长度加1。1≤pos≤ListLength(L)+1。
Status ListInsert_CL(CircleList &L, int pos, ElemType e) {
    if (!L) {                       // 线性表是否存在
        printf("线性表未初始化。");
        return INFEASIBLE;
    }

    CircleList p = L;               // 定义一个结构体指针变量p,指向线性表第一个结点(若为空,则指向头结点)。
    int j = 0;

    while ((p->next != L) && j<pos-1) {       // 寻找第i-1个结点,并令p指向其前趋。
        p = p->next;                // p非空,且j<i-1,说明指针位于线性表内
        ++j;
    }
    //pos<1  pos-1>j
    if (j<pos-1) {                  // 插入位置是否合法(第i个结点存在,插入的位置在表内)
        printf("插入位置不合法。");
        return ERROR;
    }
    CircleList s = (CircleList) malloc(sizeof(LNode));// 生成新结点
    s->data = e;                    // 将插入的元素值 赋给 新生成结点的数据域
    s->next = p->next;              // 新结点 指向 下一个结点 (即将结点i-1中指向第i个元素的指针域p->next,赋给新结点的指针域s->next)
    p->next = s;                    // 插入位置上一结点 指向 新结点(即将指向新生成结点的指针s,赋给第i-1个元素的指针域p->next)
    printf("插入的位置:%d, 插入的元素:%d", pos, e);
    return OK;
}// ListInsert_CL 算法2.9更改

// 操作结果:删除L的第pos个数据元素,并用e返回其值,L的长度减1。1≤pos≤ListLength(L)。
Status ListDelete_CL(CircleList &L, int pos, ElemType &e) {
    if (!L) {                       // 线性表是否存在
        printf("线性表未初始化。");
        return INFEASIBLE;
    }
    CircleList p = L;               // 定义一个结构体指针变量p,指向线性表起始位置(头结点)L。
    int j = 0;
    while ((p->next != L) && j<pos-1) { // 寻找第i个结点,并令p指向其前趋。
        p = p->next;
        ++j;
    }
    if ((p->next == L) || pos<1 || j<pos-1)// 删除位置是否合法(结点存在,删除的位置在表内)
        return ERROR;
    CircleList q = p->next;         // 使q指向i-1结点(将结点i-1中指向结点i的指针域,赋给指针变量q)
    p->next = q->next;              // 将结点i中指向结点i+1的指针域,赋给结点i-1的指针域
    e = q->data;                    // 要删除结点的数据域,赋给e
    free(q);                        // 释放指针变量q
    return OK;
}// ListDelete_CL 算法2.10更改

// 操作结果:依次对L的每个数据元素调用函数visit()。一旦vistit()失败,刚操作失败。
Status visit(ElemType e) {
    printf("%d->", e);
    return OK;
}
Status ListTraverse_CL(CircleList L, Status (*pfn_visit)(ElemType)) {
    if(!L) {
        printf("线性表未初始化。");
        return ERROR;
    }
    if(L->next == L) {
        printf("线性表为空表。");
        return ERROR;
    }
    CircleList p = L->next;          // p指向第一个结点
    while(p != L) {
        visit(p->data);
        p = p->next;
    }
    return OK;
}// ListTraverse

// 创建随机表,包含10个随机数(头插法)。
void CreateList_CL_10(CircleList &L) {
    // 提供随机数种子
    srand((unsigned)time(NULL));
    // 生成头结点
    L = (CircleList)malloc(sizeof(LNode));
    if(!L) {
        printf("存储分配失败!!!");
        exit(OVERFLOW);             // exit(-1)程序异常退出
    }
    L->next = L;                    // 头结点指针域指向本身
    for (int i=0; i<10; i++) {      // 生成新结点
        CircleList p = (CircleList)malloc(sizeof(LNode));
        // scanf("%d", &p->data);      // 输入元素值 赋给新生成结点的数据域
        p->data = rand()%100;
        p->next = L->next;          // 插入到表头
        L->next = p;
        printf("%d ", p->data);     // 查看是否插入了新的元素
    }
}// CreateList_CL_10

// 逆位序输入(随机产生)n个元素的值,建立带表头结点的线性表L(头插法)。
void CreateList_CL_Head(CircleList &L, int n) {
    srand((unsigned)time(NULL));    // 初始化随机数种子
    // 先建立一个带头结点的单链表
    L = (CircleList)malloc(sizeof(LNode));
    if(!L) {
        printf("存储分配失败!!!");
        exit(OVERFLOW);             // exit(-1)程序异常退出
    }
    L->next = L;                    // 头结点指针域指向本身
    for (int i=n; i>0; --i) {
        CircleList p = (CircleList)malloc(sizeof(LNode));// 生成新结点
        // scanf("%d", &p->data);    // 输入元素值
        // 随机生成100以内的数字
        p->data = rand()%100;       // 将生成的元素值赋给新生成结点的数据域
        // 插入到表头
        p->next = L->next;          // 使新结点的指针域 指向 上一次生成的结点
        L->next = p;                // 头结点的指针域 指向 新生成的结点(将指向新结点的指针p 赋给 头结点的指针域)
    }
}// CreateList_CL 算法2.11更改

// 顺位序输入(随机产生)n个元素的值,建立带表头结点的线性表L(尾插法)。
void CreateList_CL_Tail(CircleList &L, int n) {
    srand((unsigned)time(NULL));    // 初始化随机数种子
    // 先建立一个带头结点的单链表
    L = (CircleList)malloc(sizeof(LNode));
    if(!L) {
        printf("存储分配失败!!!");
        exit(OVERFLOW);             // exit(-1)程序异常退出
    }
    L->next = L;                    // 头结点指针域指向本身
    for (int i=0; i<n; ++i) {
        CircleList p = (CircleList)malloc(sizeof(LNode));
        // scanf("%d", &p->data);    // 输入元素值
        p->data = rand()%100;       // 随机生成100以内的数字,将生成的元素值赋给新生成结点的数据域
        // 插入到表尾
        L->next = p;                // 上一结点 指向 新生成的结点(将新生成结点的指针域 赋给 上一结点的指针域)
        p->next = L;                // 将新结点的指针域 指向 头结点
    }
}

// 初始化菜单
void initMenu() {
    printf("\n\t\t*****************************************\n");
    printf("\n\t\t\t\t  循环链表\n");
    printf("\n\t\t  1.创建随机表\t\t  2.构造空线性表\n\t\t  3.销毁线性表\t\t  4.清空线性表\n\t\t  5.线性表是否为空\t  6.线性表的长度");
    printf("\n\t\t  7.查找表中元素\t  8.插入新元素\n\t\t  9.删除某个元素\t 10.遍历线性表\n\t\t 11.回到主菜单\t\t  0.退出");
}
// 回到主菜单
void mainMenu() {
    printf("\n\t\t*****************************************\n");
    printf("\n\t\t\t\t  循环链表\n");
    printf("\n\t\t  1.创建随机表\t\t  2.构造空线性表\n\t\t  3.销毁线性表\t\t  4.清空线性表\n\t\t  5.线性表是否为空\t  6.线性表的长度");
    printf("\n\t\t  7.查找表中元素\t  8.插入新元素\n\t\t  9.删除某个元素\t 10.遍历线性表\n\t\t 11.回到主菜单\t\t  0.退出");
}
int main() {
    CircleList L = NULL;
    initMenu();
    int select = -1;
    while(select != 0)
    {
        printf("\n\n请选择你的操作:");
        scanf("%d", &select);
        switch(select)
        {
        case 1:// 创建随机表
            printf("请输入要创建的随机表元素个数:");
            int nElem;
            scanf("%d", &nElem);
            CreateList_CL_Head(L, nElem);
            printf("创建随机链表:");
            ListTraverse_CL(L, visit);
            break;
        case 2:// 构造空线性表
            printf("构造一个空的线性表L。");
            InitList_CL(L);
            break;
        case 3:// 销毁线性表
            printf("销毁线性表L。");
            DestroyList_CL(L);
            break;
        case 4:// 清空线性表
            printf("将L重置为空表。");
            ClearList_CL(L);
            break;
        case 5:// 线性表是否为空
            ListEmpty_CL(L);
            break;
        case 6:// 线性表的长度
            {
                int lLength = ListLength_CL(L);
                if(lLength != -1) printf("线性表的长度为: %d ", lLength);
            }
            break;
        case 7:// 查找表中元素
            {
                int nSearchOption = -1;
                while(nSearchOption!=0 && nSearchOption!=11)
                {
                    printf("1.按位置查找\t  2.按元素查找\t  11.回到主菜单\t  0.退出查找\n请选择你的操作:");
                    scanf("%d", &nSearchOption);
                    switch(nSearchOption)
                    {
                    case 1:// 1.按位置查找
                        {
                            int pos;
                            ElemType e;
                            printf("请输入要查找的位置:");
                            scanf("%d", &pos);
                            int ret = GetElem_CL(L, pos, e);
                            if (ret == -1) {
                                printf("\n");
                                break;
                            } else if (ret == 0) {
                                printf("查找位置不正确!\n");
                                break;
                            }
                            printf("第%d个元素的值为:%d ", pos, e);
                            ElemType pre_e, next_e;
                            if(PriorElem_CL(L, e, pre_e))
                                printf("前一个元素为:%d ", pre_e);
                            if(NextElem_Sq(L, e, next_e))
                                printf("后一个元素为:%d", next_e);
                            printf("\n");
                        }
                        break;// 2.按元素查找
                    case 2:
                        {
                            printf("请输入要查找的元素:");
                            ElemType e;
                            scanf("%d", &e);
                            int pos = LocateElem_CL(L, e, compare);
                            if (pos == -1) {
                                printf("\n");
                                break;
                            } else if (pos == 0) {
                                printf("没有值为%d的元素。\n", e);
                                break;
                            }
                            printf("值为%d是表中的第%d个元素。\n", e, pos);
                        }
                        break;
                    case 11:// 11.回到主菜单
                        mainMenu();
                        break;
                    case 0:// 0.退出查找
                        break;
                    default:
                        printf("请输入正确的数字!!!\n");
                        break;
                    }
                }
            }
            break;
        case 8:// 插入新元素
            {
                ElemType e;
                int pos;
                int nInsertOption = -1;
                while(nInsertOption)
                {
                    printf("请输入要插入的元素位置和元素的值:");
                    scanf("%d %d", &pos, &e);
                    int ret = ListInsert_CL(L, pos, e);
                    // 线性表未初始化,中断循环
                    if(ret == -1)
                        break;
                    // 插入位置不合法,中断循环
                    else if(!ret)
                        break;
                    // 插入元素
                    printf("\n现在线性表为:");
                    ListTraverse_CL(L, visit);
                    printf("\n1.是  0.否  是否继续: ");
                    scanf("%d", &nInsertOption);
                }
            }
            break;
        case 9:// 删除某个元素
            {
                int nDeleteOption = -1;
                while(nDeleteOption!=0 && nDeleteOption!=11)
                {
                    printf("1.按位置删除\t  2.按元素删除\t  11.回到主菜单\t  0.退出删除\n请选择你的操作:");
                    scanf("%d", &nDeleteOption);
                    switch(nDeleteOption)
                    {
                    case 1: // 1.按位置删除
                        {
                            ElemType e;
                            int pos;
                            printf("请输入要删除的位置:");
                            scanf("%d", &pos);
                            int ret = ListDelete_CL(L, pos, e);
                            if (ret == -1) {
                                printf("\n");
                                break;
                            } else if (ret == 0) {
                                printf("删除位置不正确!\n");
                                break;
                            }
                            printf("现在线性表为:");
                            ListTraverse_CL(L, visit);
                            printf("\n");
                        }
                        break;
                    case 2: // 2.按元素删除
                        {
                            printf("请输入要删除的元素:");
                            ElemType e;
                            scanf("%d", &e);
                            // 删除的将是第一个出现的元素
                            int pos = LocateElem_CL(L, e, compare);
                            if (pos == -1) {
                                printf("\n");
                                break;
                            } else if (pos == 0) {
                                printf("没有值为%d的元素。", e);
                                break;
                            }
                            printf("值为%d是表中的第%d个元素。", e, pos);
                            ListDelete_CL(L, pos, e);
                            printf("\n现在线性表为:");
                            ListTraverse_CL(L, visit);
                            printf("\n");
                        }
                        break;
                    case 11:// 11.回到主菜单
                        mainMenu();
                        break;
                    case 0:// 0.退出查找
                        break;
                    default:
                        printf("请输入正确的数字!!!\n");
                        break;
                    }
                }
            }
            break;
        case 10:// 遍历线性表
            printf("遍历线性表:");
            ListTraverse_CL(L, visit);
            break;
        case 11:// 回到主菜单
            mainMenu();
            break;
        case 0:// 退出
            break;
        default:
            printf("请输入正确的数字!!!");
            break;
        }
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值