单循环链表(基于c语言)
#include <stdio.h> #include <stdlib.h> #include <assert.h> typedef int LDataType; typedef struct Linklist{ LDataType data; struct Linklist *next; }Linklist,*pLinklist; pLinklist BuyNewNode(LDataType data); //动态生成新结点 void InitLinklist(pLinklist *pL); //初始化单链表 void PushBackLinklist(pLinklist *pL,LDataType data); //尾插 void PushFrontLinklist(pLinklist *pL,LDataType data); //头插 void PopBackLinklist(pLinklist* pL); //尾删 void PopFrontLinklist(pLinklist *pL); //头删 void PrintLinklist(Linklist *pL); //打印单链表 pLinklist FindLinklist(pLinklist *pL,LDataType data); //查找指定元素,返回元素位置 //void InsertLinklist(pLinklist *pL,pLinklist p,LDataType data); //指定位置插入 void RemoveLinklist(pLinklist* pL,LDataType data); //删除第一个指定元素 void RemoveAllLinklist(pLinklist *pL,LDataType data); //删除所有指定元素 int IsEmptyLinklist(pLinklist pL); //判断链表是否为空 void DestoryLinklist(pLinklist *pL); //销毁单链表 int main(void){ Linklist *first = NULL; InitLinklist(&first); int people_num = 10; int each = 3; int return_num = 0; for (int i=0;i<10;i++){ PushBackLinklist(&first,i+1); } int i = 1; Linklist *another = first; Linklist *pre; PrintLinklist(first); puts(" "); while(1){ if(another->next == first && first->next == another && first == another){ PrintLinklist(first); break; } if(i%3 == 0){ pre = another->next; RemoveLinklist(&first,another->data); i++; another = pre; PrintLinklist(first); puts(" "); }else{ another = another->next; i++; } } // Linklist *first = NULL; // InitLinklist(&first); // for (int i=0;i<10;i++){ // PushBackLinklist(&first,i+1); // } // PrintLinklist(first); // puts(" "); // RemoveLinklist(&first,7); // PrintLinklist(first); } //循环链表与开辟内存区域无关 pLinklist BuyNewNode(LDataType data){ pLinklist NewNode = (pLinklist)malloc(sizeof(Linklist)); if (NewNode == NULL){ printf("动态开辟内存空间失败\n"); return NULL; } NewNode->data = data; NewNode->next = NULL; return NewNode; } void InitLinklist(pLinklist *pL){ assert(pL != NULL); //初始化操作 (*pL) = NULL; } void PushBackLinklist(pLinklist *pL,LDataType data){ //主要就是从尾部插入的元素应该要指向头指针 assert(pL != NULL); //尾插一个数据域为data的结点 pLinklist NewNode = BuyNewNode(data); if(*pL == NULL){ *pL = NewNode; NewNode->next = *pL; return ; } pLinklist cur = *pL; while(cur->next != *pL){ cur = cur->next; } NewNode->next = cur->next; cur->next = NewNode; } void PushFrontLinklist(pLinklist *pL,LDataType data){ assert(pL != NULL); //头插一个数据域为data的结点 pLinklist NewNode = BuyNewNode(data); if(*pL == NULL){ *pL = NewNode; NewNode->next = *pL; return ; } NewNode->next = *pL; *pL = NewNode; pLinklist pre = NewNode->next; while(pre->next != NewNode->next){ pre = pre->next; } pre->next = *pL; } int IsEmptyLinklist(pLinklist pL){ return (pL == NULL); //判断无头单链表是否为空 } void PopBackLinklist(pLinklist *pL){ assert(pL != NULL); //尾删 if(IsEmptyLinklist(*pL)){ puts("链表为空,删除失败"); return ; } pLinklist cur = *pL; pLinklist pre; if(cur->next == *pL){ //只有一个结点 *pL = NULL; free(cur); cur = NULL; return ; } while(cur->next != *pL){ pre = cur; cur = cur->next; } pre->next = *pL; free(cur); cur = NULL; } void PopFrontLinklist(pLinklist *pL){ assert(pL != NULL); //头删,既是删除第一个结点 if(*pL == NULL){ printf(" 链表为空,删除失败"); return ; } pLinklist cur = *pL; if(cur->next == *pL){ *pL = NULL; free(cur); cur = NULL; return ; } *pL = cur->next; free(cur); cur = NULL; } pLinklist FindLinklist(pLinklist *pL,LDataType data){ assert( pL != NULL); //找到第一个数据为data的结点 pLinklist cur = *pL; while(cur->next != *pL){ if (cur->data == data){ return cur; } cur = cur->next; } if(cur->data == data){ return cur; } return NULL; } //void InsertLinklist(pLinklist *pL,pLinklist p,LDataType data){ // assert(pL != NULL); //xiangp结点之前插入一个数据为data的元素 // pLinklist NewNode = BuyNewNode(data); // pLinklist cur = *pL; // while(cur->next != p){ // cur = cur->next; // } // NewNode->next = p; // cur->next = NewNode; //} void RemoveLinklist(pLinklist *pL,LDataType data){ assert(pL != NULL); //删除第一个数据域为data的结点 pLinklist cur = NULL; pLinklist p = *pL; pLinklist pre = NULL; cur = FindLinklist(pL,data); if (cur == NULL){ printf("未找到要删除的元素"); return ; } if (*pL == cur){ //位于第一个结点 // *pL = cur->next; // free(cur); // cur = NULL; // return ; pLinklist each_node = *pL; while(each_node->next != *pL){ each_node = each_node->next; } each_node->next = (*pL)->next; *pL = (*pL)->next; free(cur); cur = NULL; return ; } while(p != cur){ pre = p; p = p->next; } pre->next = cur->next; free(cur); cur = NULL; } void RemoveAllLinklist(pLinklist *pL,LDataType data){ assert(pL != NULL); //删除每一个数据域都是data的结点 pLinklist cur = NULL; pLinklist p = *pL; pLinklist pre = *pL; while(p->next != *pL){ if (p->data == data && (*pL) == p){ //第一个结点是 pLinklist each_node = *pL; while(each_node->next != *pL){ each_node = each_node->next; } each_node->next = (*pL)->next; pre = p; p = p->next; *pL = p; free(pre); pre = NULL; } else if(p->data == data){ //后续结点是 cur = p; p = p->next; pre->next = p; free(cur); cur = NULL; } else{ //此结点不是 pre = p; p = p->next; } } } void PrintLinklist(Linklist *pL){ pLinklist cur = pL; //打印链表 if(cur->next == pL){ printf("%d--->",cur->data); }else{ while(cur->next != pL){ printf("%d--->",cur->data); cur = cur->next; } printf("%d--->",cur->data); } printf("头"); } void DestoryLinklist(pLinklist *pL){ assert(pL != NULL); //摧毁链表 pLinklist cur = *pL; pLinklist pre = NULL; if (*pL == NULL){ printf("链表为空"); return ; } if (cur->next = *pL){ *pL = NULL; free(cur); cur = NULL; return ; } while(cur->next != *pL){ pre = cur; cur = cur->next; free(pre); pre = NULL; } }
这个代码是我在单链表的基础上改的,顺便实现了一下一个Josephus算法。其他的值是可以输入的。
在写这个代码的时候唯一难一点的就是头插,头删这两个操作。
头插:首先要判断是否为空,如果为空的话直接插入,然后再指向自己或者指向*pL就行了;但是如果有元素的话,头插就不是那么简单了,我们可以看一下下面的图,很明显,我们需要将新的结点的link域指向*pL,然后将*pL指向新的结点,这还没有完!!
然后现在的链表并不是我们想要的一个循环链表,所以我们要找到最后一个结点再让他指向新的结点。

头删:我感觉这个和上面头删是一样的,上面的只要掌握了,自然也就会头部删除了。先判断是否为空……

浙公网安备 33010602011771号