zoukankan      html  css  js  c++  java
  • 数据结构(一)线性表循环链表

    (一)定义

    将单链表中终端结点的指针端有空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表称为单循环链表,检测循环链表

    (二)优点

    无论从链表的哪一个结点出发,都可以访问到所有的结点

    (三)结构

    对于单循环链表:
    使用尾指针,可以在O(1)时间内找到终端结点和开始结点
    使用头指针,我们只能在O(1)时间内找到开始结点。
    所以选择尾指针的效率更好

    带有头结点

    不带头结点

    (四)实现循环链表(使用尾指针,不带头结点)

    #define _CRT_SECURE_NO_WARNINGS
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    #define OK 1
    #define ERROR 0
    #define TRUE 1
    #define FALSE 0
    
    typedef int ElemType;
    typedef int Status;
    
    typedef struct Node
    {
        ElemType data;
        struct Node* next;
    }Node;
    
    typedef struct Node* CLinkList;
    
    //四个基本操作,初始,清空,判断是否为空,获取长度
    Status InitList(CLinkList* L);
    Status ClearList(CLinkList* rear);
    Status ListEmpty(CLinkList rear);
    int ListLength(CLinkList rear);
    
    //四个元素操作,插入,删除,两种查找
    Status GetElem(CLinkList rear, int i, ElemType* e);
    int LocateElem(CLinkList rear, ElemType e);
    Status ListInsert(CLinkList* rear, int i, ElemType e);
    Status ListDelete(CLinkList* rear, int i, ElemType* e);
    
    //指定开始位置来打印数据
    void PrintListByIndex(CLinkList rear,int index);
    //用来打印链表
    void PrintList(CLinkList rear);
    //四个基本操作,初始,清空,判断是否为空,获取长度
    //初始化不带头结点的链表
    Status InitList(CLinkList* L)
    {
        CLinkList rear,q;    //rear是尾结点
        ElemType item;
        rear = q = NULL;
    
        printf("please enter the value of node(enter 0 to finish Initialize)
    ");
        while (1)
        {
            scanf("%d", &item);
            fflush(stdin);
            if (item == 0)
                break;
    
            if ((*L)==NULL)    //进行初始化
            {
                *L = (CLinkList)malloc(sizeof(Node));
                if (!(*L))
                    return ERROR;
                (*L)->data = item;
                (*L)->next = *L;    //自己指向自己
                rear = *L;    //设置尾指针位置
            }
            else     //已初始完毕,进行数据插入
            {
                //生成新的节点,根据尾指针添加节点,并实时更新尾指针。注意这里数据插入是尾插法
                q = (CLinkList)malloc(sizeof(Node));
                q->data = item;
                q->next = rear->next;
                rear->next = q;
                rear = q;
            }
        }
        *L = rear;    //更新指针位置,使原来指针指向链表尾部
        return OK;
    }
    
    
    //清空链表
    Status ClearList(CLinkList* rear)
    {
        CLinkList q, p;
        q = (*rear)->next;    //找到第一个结点
        (*rear)->next = NULL;
        while (q)
        {
            p = q;
            q = q->next;
            free(p);
        }
        return OK;
    }
    
    //判断链表是否为空,若是头指针和尾指针一样,为空
    Status ListEmpty(CLinkList rear)
    {
        if (rear->next == rear)    //头指针等于尾指针
            return TRUE;
        return FALSE;
    }
    // 
    //获取列表长度
    int ListLength(CLinkList rear)
    {
        int length = 1;
        CLinkList head = rear->next;
        while (head != rear)
        {
            head = head->next;
            length++;
        }
        return length;
    }
    
    //四个元素操作,插入,删除,两种查找
    //按照索引查找,获取元素
    Status GetElem(CLinkList rear, int i, ElemType* e)
    {
        int j=1;
        CLinkList q=rear;
        if (i<1 || i>ListLength(rear))
            return ERROR;
        for (; j <= i;j++)
        {
            q = q->next;
        }
        *e = q->data;
        return OK;
    }
    
    //按照元素进行查找,获取索引
    int LocateElem(CLinkList rear, ElemType e)
    {
        int j;
        CLinkList q = rear;
        for (j = 1; j <= ListLength(rear);j++)
        {
            q = q->next;
            if (q->data == e)
                break;
        }
        return j;
    }
    
    //按照索引进行插入数据
    Status ListInsert(CLinkList* rear, int i, ElemType e)
    {
        if (*rear == NULL && i > ListLength(*rear)+1)
            return ERROR;
    
        int j = 1;
        CLinkList q;
        CLinkList start = (*rear);    //若是想插入到第一个位置,必须从尾指针开始
        for (; j < i; j++)
            start = start->next;    //去获取插入的前一个位置
    
        //开始创建一个新的节点
        q = (CLinkList)malloc(sizeof(Node));
        q->data = e;
        q->next = start->next;
        start->next = q;
    
        return OK;
    }
    
    //进行元素删除
    Status ListDelete(CLinkList* rear, int i, ElemType* e)
    {
        if ((*rear) == NULL || i>ListLength(*rear))
            return ERROR;
    
        int j=1;
        CLinkList q, p;
        q = *rear;
    
        for (; j < i; j++)
            q = q->next;    //找到前一个元素
        p = q->next;    //p是我们要删除的那个元素
        q->next = p->next;
        *e = p->data;
        free(p);
        
        return OK;
    }
    
    //从指定位置开始打印数据(这个才是体现循环链表的特性)
    void PrintListByIndex(CLinkList rear, int index)
    {
        CLinkList start=rear;
        for (int i = 1; i <= index;i++)
            start = start->next;
        rear = start;
        while (start->next!=rear)
        {
            printf("%d ", start->data);
            start = start->next;
        }
        printf("%d
    ", start->data);
    }
    
    //用来打印链表
    void PrintList(CLinkList rear)    //L是尾指针
    {
        CLinkList q = rear->next;    //获取头指针
        while (q!=rear)
        {
            printf("%d ", q->data);
            q = q->next;
        }
        printf("%d
    ", rear->data);
    }
    int main()
    {
        CLinkList rear,L=NULL;
        ElemType e;
        InitList(&L);    //初始化后,L变为尾指针
        rear = L;
        PrintList(rear);
        ListInsert(&rear, 3, 999);
        PrintList(rear);
        ListDelete(&rear, 3, &e);
        printf("delete:%d
    ", e);
        GetElem(rear, 4, &e);
        printf("get element:%d
    ", e);
        printf("get index:%d by 33
    ", LocateElem(rear, 33));
        PrintListByIndex(rear, 5);
        system("pause");
        return 0;
    }
    注意:测试时需要长度超过5,输入的数里面含有33,以便查找,需要插入999这个数。具体自己修改,这里不在重复了

    (五)优点

    1.可以从任意位置访问所有节点
    2.若是想上面使用尾指针构造循环链表,那么开始结点和终端结点的时间复杂度都是O(1)
  • 相关阅读:
    语句结构1练习
    语句结构(1)
    常用dos命令(4)
    常用dos命令(3)
    常用dos命令(2)
    常用dos命令(1)
    因式分解 · Factor Combinations
    电话号码的字母组合 · Letter Combinations of a Phone Number
    286 walls and gate最近的出口
    286被围绕的区域 · Surrounded Regions
  • 原文地址:https://www.cnblogs.com/ssyfj/p/9424850.html
Copyright © 2011-2022 走看看