数据结构(一)线性表循环链表
(一)定义
将单链表中终端结点的指针端有空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表称为单循环链表,检测循环链表
(二)优点
无论从链表的哪一个结点出发,都可以访问到所有的结点
(三)结构
对于单循环链表: 使用尾指针,可以在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)\n"); 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\n", start->data); } //用来打印链表 void PrintList(CLinkList rear) //L是尾指针 { CLinkList q = rear->next; //获取头指针 while (q!=rear) { printf("%d ", q->data); q = q->next; } printf("%d\n", 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\n", e); GetElem(rear, 4, &e); printf("get element:%d\n", e); printf("get index:%d by 33\n", LocateElem(rear, 33)); PrintListByIndex(rear, 5); system("pause"); return 0; }
注意:测试时需要长度超过5,输入的数里面含有33,以便查找,需要插入999这个数。具体自己修改,这里不在重复了
(五)优点
1.可以从任意位置访问所有节点 2.若是想上面使用尾指针构造循环链表,那么开始结点和终端结点的时间复杂度都是O(1)