单向循环链表是一个收尾相接的链表,将单链表的最后一个指针域改由NULL改成指向表头结点这就是单链式的循环链表,并称为循环单链表。
web
带头结点的循环单链表的各类操做的算法实现与带头结点单链表的算法实现相似,差异仅在于算法判别当前结点p是否为尾结点的条件不一样。单链表中的判别条件为p!=NULL或p->next!=NULL,而单循环链表判别条件是p!=L或p->next!=L。算法
在循环单链表中附设尾指针有时候比附设头指针更简单。如:在用头指针的循环单链表中找a1的时间复杂度是O(1),找an须要从头找到尾,时间复杂度是O(n),若是用为指针rear,找开始结点和终端结点的存储位置分别是rear->next->next和rear。svg
*L = (LinkList)malloc(sizeof(Node)); (*L)->data = item; (*L)->next = *L;
temp->data = item; // 新节点指向头结点 temp->next = *L; // 尾节点指向新结点 target->next = temp;
temp->data = item; // 新节点指向头结点 temp->next = *L; // 尾节点指向新结点 target->next = temp;
// ElemType类型根据实际状况而定,这里假设为int typedef int ElemType; // 定义结点 typedef struct Node { ElemType data; struct Node *next; } Node; typedef struct Node * LinkList;
// 方法一 void CreateList(LinkList *L) { int item; LinkList temp = NULL; LinkList target = NULL; printf("Please input data and enter 0 end:\n"); while(1) { scanf("%d",&item); if(item == 0) break; // 若是输入的链表是空,则建立一个新的结点,使其next指针指向本身:(*head)->next=*head if(*L == NULL) { *L = (LinkList)malloc(sizeof(Node)); if(!L) { exit(0); } (*L)->data = item; (*L)->next = *L; } else { // 输入的链表不是空的,寻找链表的尾结点,使尾结点的next=新结点,新结点的next指向头结点 for (target = *L; target->next != *L; target = target->next); temp = (LinkList)malloc(sizeof(Node)); if(!temp) { return; } temp->data = item; // 新节点指向头结点 temp->next = *L; // 尾节点指向新结点 target->next = temp; } } }
// 方法二 void CreateList(LinkList *L){ int item; LinkList temp = NULL; LinkList r = NULL; printf("Please input data and enter 0 end:\n"); while (1) { scanf("%d",&item); if (item == 0) { break; } // 第一次建立 if(*L == NULL){ *L = (LinkList)malloc(sizeof(Node)); if(!*L) { return; } (*L)->data = item; (*L)->next = *L; r = *L; } else { temp = (LinkList)malloc(sizeof(Node)); if(!temp) { return; } temp->data = item; temp->next = *L; r->next = temp; r = temp; } } }
// 遍历循环链表,循环链表的遍历最好用do while语句,由于头结点就有值 void show(LinkList p) { // 若是链表是空 if(p == NULL){ printf("打印的链表为空!\n"); return; } else { LinkList temp; temp = p; do { printf("%5d",temp->data); temp = temp->next; } while (temp != p); printf("\n"); } }
// 循环链表插入数据 void ListInsert(LinkList *L, int place, int num) { LinkList temp ,target; int i; // 若是插入的位置为1,则属于插入首元结点,因此须要特殊处理 if (place == 1) { // 建立新结点temp,并判断是否建立成功,成功则赋值,不然直接return; temp = (LinkList)malloc(sizeof(Node)); if (temp == NULL) { return; } // 找到链表最后的结点_尾结点 temp->data = num; for (target = *L; target->next != *L; target = target->next); // 让新结点的next执行头结点 temp->next = *L; // 尾节点的next 指向新的头结点 target->next = temp; // 让头指针指向temp(临时的新节点) *L = temp; } else { // 若是插入的位置在其余位置 // 建立新结点temp,并判断是否建立成功,成功则赋值,不然return temp = (LinkList)malloc(sizeof(Node)); if (temp == NULL) { return; } // 先找到插入的位置,若是超过链表长度,则自动插入队尾 temp->data = num; for ( i = 1,target = *L; target->next != *L && i != place - 1; target = target->next,i++) ; // 经过target找到要插入位置的前一个结点, 让target->next = temp; temp->next = target->next; // 插入结点的前驱指向新结点,新结点的next 指向target原来的next位置 target->next = temp; } }
// 循环链表删除元素 void LinkListDelete(LinkList *L, int place) { LinkList temp,target; int i; // temp 指向链表首元结点 temp = *L; if(temp == NULL) { return; } if (place == 1) { // 若是删除到只剩下首元结点了,则直接将*L置空 if((*L)->next == (*L)){ (*L) = NULL; return; } // 链表还有不少数据,可是删除的是首结点 // 找到尾结点, 使得尾结点next 指向头结点的下一个结点 target->next = (*L)->next for (target = *L; target->next != *L; target = target->next); temp = *L; *L = (*L)->next; // 新结点作为头结点,则释放原来的头结点 target->next = *L; free(temp); } else { // 若是删除其余结点--其余结点 // 找到删除结点前一个结点target for(i = 1,target = *L; target->next != *L && i != place -1; target = target->next,i++) ; // 使得target->next 指向下一个结点 temp = target->next; target->next = temp->next; // 释放须要删除的结点temp free(temp); } }
int findValue(LinkList L,int value) { int i = 1; LinkList p; p = L; // 寻找链表中的结点 data == value while (p->data != value && p->next != L) { i++; p = p->next; } // 当尾结点指向头结点就会直接跳出循环,因此要额外增长一次判断尾结点的data == value; if (p->next == L && p->data != value) { return -1; } return i; }
单向线性表链式存储spa