moc 发表于 2018-9-24 10:19:15

004-循环单链表

本帖最后由 moc 于 2018-9-24 11:10 编辑

1、基本概念
循环单链表的定义:将单链表中的最后一个元素的next指向第一个元素。

        注意:头指针是链表的开始,它的指针域指向头结点,数据域存放着与整个链表相关的数据,如长度等;头指针结点不参与链表循环。
拥有的操作:
        创建链表
        销毁链表
        获取链表长度
        清空链表
        获取链表的第pos个元素
        插入元素到pos位置
        删除pos位置的元素
新增功能: 游标
        在循环链表中可以定义一个“当前”指针,这个指针即通常称的“游标”,可以通过游标来遍历元素。
循环链表的新增操作:
        将游标重置,即指向链表的第一个元素;
        获取当前游标指向的数据元素;
        将游标移动至下一个元素;
        直接指定删除链表中的某个数据元素。
2、设计与实现
1. 插入元素
        ① 普通插入元素:和单链表一样
        ② 尾插法: 和单链表一样
        ③ 头插法: 需要先求出尾结点,因为0号位置,辅助指针current跳0步,没有跳走仍留在头指针。
        ④ 判断若为第一次插入,让游标指向头结点。

void CircleList_Insert(CircleList* list, CircleListNode* node, int pos)
{
        int ret = 0, i = 0;
        TCircleList* tlist = (TCircleList*)list;
        if (tlist == NULL || node == NULL || pos < 0)
        {
                return -1;
        }

        CircleListNode* current = (CircleListNode*)tlist;
        for (i = 0; (i < pos) && (current->next != NULL); i++)
        {
                current = current->next;
        }

        node->next = current->next;// 1
        current->next = node;// 2

        // 若第一次插入
        if (tlist->length == 0)
        {
                tlist->slider = node;
        }
        tlist->length++;

        // 若头插法 current仍然指向头部
        //(原因:跳0步,没有跳走仍留在头指针,导致尾部指针指向第二个结点)       
        if (current == (CircleListNode*)tlist)
        {
                CircleListNode* last = CircleList_Get(tlist, tlist->length - 1);
                last->next = current->next;
        }
}
2. 其他操作与单链表类似。
3、优缺点与典型应用
优点:
        循环单链表在单链表的基础上功能增强啦;
        完全可以替代单链表。
缺点:
        代码复杂度提高啦。
约瑟夫问题:
        n个人围成一个圆圈,首先第一个人从1开始一个人一个人顺时针报数,报到第m个人,令其出列,然后从下一个人开始顺时针报数,报到第m个人,再令其出列,....,如此下去,求出出列顺序。

循环链表解决方案:
typedef struct _Value
{
        CircleListNode circleNode;
        int v;
}Value;

int main()
{
        int i = 0;
        CircleList* list = CircleList_Create();
        Value v1, v2, v3, v4, v5, v6, v7, v8;
        v1.v = 1;v2.v = 2;v3.v = 3;v4.v = 4;
        v5.v = 5;v6.v = 6;v7.v = 7;v8.v = 8;

        CircleList_Insert(list, (CircleListNode*)&v1, CircleList_Length(list));
        CircleList_Insert(list, (CircleListNode*)&v2, CircleList_Length(list));
        CircleList_Insert(list, (CircleListNode*)&v3, CircleList_Length(list));
        CircleList_Insert(list, (CircleListNode*)&v4, CircleList_Length(list));
        CircleList_Insert(list, (CircleListNode*)&v5, CircleList_Length(list));
        CircleList_Insert(list, (CircleListNode*)&v6, CircleList_Length(list));
        CircleList_Insert(list, (CircleListNode*)&v7, CircleList_Length(list));
        CircleList_Insert(list, (CircleListNode*)&v8, CircleList_Length(list));

        for (i = 0; i < CircleList_Length(list); i++)
        {
                // 获取游标所指的元素,然后游标下移
                Value* pv = (Value*)CircleList_Next(list);
                printf("%d\n", pv->v);
        }
        printf("\n");

        // 重置游标
        CircleList_Reset(list);

        while (CircleList_Length(list) > 0)
        {
                Value* pv = NULL;
                for (i = 0; i < 2; i++)
                {
                        CircleList_Next(list);
                }
                pv = (Value*)CircleList_Current(list);
                printf("%d\n", pv->v);
                CircleList_DeleteNode(list, (CircleListNode*)pv);
        }

        CircleList_Destory(list);

        system("pause");
        return 0;
}
完整代码:
页: [1]
查看完整版本: 004-循环单链表