循环双链表

LoopDLink.cpp 源码

/*  Copyright (C++) 2019 * Ltd. All rights reserved.
 *      Create date : 2019-08-27 11:41:04
 *================================================*/

/*
2018.8.15
注意三点:
            1.不要将循环写成if    //很尴尬,主要是我犯了这个错误,找了半天还没找出来,次日看的时候才发现,很是的尴尬
            2.循环链表的判空操做是  p->next != *L
            3.p = *L,循环体中用p->next作条件  这种写法便于对当前结点的前一结点操做,插入、删除、修改操做使用这种形式
              p = *L->next,循环体中用p作条件  这种写法便于对当前结点操做,查找、遍历使用这种形式
       4.双向链表在插入与删除时,要处理好前驱指针和后继指针,切不可遗忘。尤为是插入时,要将新点以后的结点的前驱指向新结点,这里容易被忽略
*/

#include <stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<time.h>
typedef int ElemType;        //元素类型
typedef int Status;            //返回类型
#define OK 1;                //函数运行成功返回值
#define ERROR 0;            //函数运行失败返回值

typedef struct Node
{
    struct Node *prior;            //指向前一结点的指针
    ElemType date;                //结点元素
    struct Node *next;            //指向后一结点的指针
}Node, *LoopDList;


/*
循环双链表的建立
*/
Status CreatList(LoopDList &L, int *arr, int n)
{
    int i;                    //计数器
    L = (LoopDList)malloc(sizeof(Node));                //建立头结点
    L->next = L;
    L->prior = L;

    LoopDList s,p;                                        //s用于开辟新结点,p指向表尾
    p = L;                                                //指向表尾结点

    for(i = 0; i < n; i++)
    {
        s = (LoopDList)malloc(sizeof(Node));                //开辟新结点
        s->date = arr[i];                        //为新结点赋值
        p->next = s;                                    //让表尾结点的后继结点指向新结点
        s->prior = p;                                    //让新结点的前驱结点指向p
        p = s;                                            //表尾结点指针后移
    }
    p->next = L;                                        //使表尾结点的后继指针指向头结点
    L->prior = p;                                    //头指针的前驱结点指向表尾结点
    return OK;
}

/*
循环双向链表的插入操做
*/
Status LoopInsert(LoopDList &L, int i, ElemType e)
{
    int j = 1;                //计数器,记录当前位置
    LoopDList p = L;        //指向L        //此种写法便于对当前结点的上一结点进行操做
    LoopDList s;                        //用于建立新结点
//    while(p->next && j < i)                    //判非空  判位置索引合理    //循环链表的判断非空不是这样的    2018.8.15
    while(p->next != L && j < i)
    {
        p = p->next;                //指针后移
        j++;                        //计数器加1
    }
    if(p->next == L || j > i)                    //判空    判位置索引不合理
        return ERROR;
    s = (LoopDList)malloc(sizeof(Node));            //开辟新结点s
    s->date = e;                                //为s的数据域赋值

    s->prior = p->prior;
    s->next = p;
    p->prior->next = s;
    p->prior = s;


#if 0
    p->next->prior= s;                            //使插入结点后的下一结点的前驱指向s
    s->next = p->next;                            //使s的后继结点等于p的后继结点
    s->prior= p;                                //使s的前驱结点等于p
    p->next = s;                                //使p得后继结点等于s
#endif
    return OK;
}

/*
循环双向链表的删除操做
*/
Status DelList(LoopDList &L, int i, ElemType *e)
{
    int j = 1;                //记录当前位置
    LoopDList p = L;        //指向链表
    LoopDList s;                        //用于释放要删除的结点
    while(p->next != L && j < i)                    //判非空   判索引位置有效
    {
        p = p->next;                //指针后移
        j++;                        //计数器加1
    }
    if(p->next == L || j > i)                    //判空     判索引位置无效
        return ERROR;
    s = p->next;                    //使s指向p
    *e = s->date;                    //将要删除的结点数据赋值给e
    p->next = s->next;                //使p的后继结点等于r的后继结点
    s->next->prior = p;                //使s的后继的前驱结点等于p
    free(s);                        //释放s结点
    return OK;
}

/*
循环双链表的修改操做
*/
Status UpdateList(LoopDList *L, int i, ElemType e)
{
    int j = 1;                //记录当前位置
    LoopDList r = (*L)->next;            //指向第一个结点    //此种写法便于岁当前结点操做
    while(r != *L && j < i)                        //判非空    判位置索引有效
    {
        r = r->next;                    //指针后移
        j++;                            //计数器加1
    }
    if(r == *L || j > i)                        //判空      判位置索引无效
        return ERROR;
    r->date = e;                        //使r的数据域等于 e
    return OK;
}

/*
循环双链表的查找
*/
Status GetElem(LoopDList L, int i, ElemType *e)
{
    int j = 0;                    //计数器
    LoopDList p = L->next;        //指向第一个结点
    while(p != L && j < i)                //判非空     判位置索引有效
    {
        p = p->next;            //指针后移
        j++;                    //计数器加1
    }
    if(p == L || j > i)                //判空   判位置索引无效
        return ERROR;
    *e = p->date;                //将p的数据域内容赋值给e
    return OK;
}

/*
循环双链表的正序遍历
*/
void PrintList1(LoopDList L)
{
    LoopDList p = L->next;            //指向L第一个结点
    if(p == L)                    //判空
        printf("表空\n");
    while(p != L)                //判非空
    {
        if(p->next != L)
            printf("[%d] -> ", p->date);
        else
            printf("[%d]",p->date);
        p = p->next;
    }
    printf("\n");
}

/*
循环双链表的倒序遍历
*/
void PrintList2(LoopDList L)
{
    LoopDList p = L->prior;            //指向L倒数第一个结点
    if(p == L)                        //判空
        printf("表空\n");
    while(p != L)            //判非空
    {
        if(p->prior != L)
            printf("[%d] -> ", p->date);
        else
            printf("[%d]",p->date);
        p = p->prior;
    }
    printf("\n");
}


int main()
{
    LoopDList L = NULL;            //建立链表L
    int i, e;            //i为元素位置,e为元素内容

    int n = 0;
    int arr[10] = {0,1,2,3,4,5,6,7,8,9};
    n = sizeof(arr)/sizeof(arr[0]);


    while(true)
    {
        printf("请选择对线性链表的操做:\n");
        printf("1.建立\n");
        printf("2.插入\n");
        printf("3.删除\n");
        printf("4.查找\n");
        printf("5.修改\n");
        printf("6.正序输出\n");
        printf("7.倒序输出\n");
        printf("8.退出\n");
        int a;
        scanf("%d", &a);
        switch(a)
        {
            case 1:
                if(CreatList(L, arr, n))
                    printf("建立成功\n");
                else
                    printf("建立失败\n");
                break;
            case 2:
                printf("请输入须要插入的位置:");
                scanf("%d", &i);
                printf("请输入须要插入的元素:");
                scanf("%d", &e);
                if(LoopInsert(L, i, e))
                    printf("插入成功\n");
                else
                    printf("插入失败\n");
                break;
            case 3:
                printf("请输入须要删除的位置:");
                scanf("%d", &i);
                if(DelList(L, i, &e))
                    printf("删除成功\n");
                else
                    printf("删除失败\n");
                break;
            case 4:
                printf("请输入须要查找的位置:");
                scanf("%d", &i);
                GetElem(L, i, &e);
                printf("第%d个元素为%d\n",i,e);
                break;
            case 5:
                printf("请输入须要修改的位置:");
                scanf("%d", &i);
                printf("请输入新的的元素:");
                scanf("%d", &e);
                if(UpdateList(&L, i, e))
                    printf("修改为功\n");
                else
                    printf("修改失败\n");
                break;
            case 6:
                if(L == NULL)
                {
                    printf("表还未建立\n");
                    break;
                }
                PrintList1(L);
                break;
            case 7:
                if(L == NULL)
                {
                    printf("表还未建立\n");
                    break;
                }
                PrintList2(L);
                break;
            case 8:
                return -1;
            default:
                printf("选择错误\n");
                break;
        }
    }
    return 0;
}

 

参考

双链表实现1      实现2   html

图解链表函数

循环单链表oop

相关文章
相关标签/搜索