动态游标for循环_数据结构系列循环链表
生活随笔
收集整理的這篇文章主要介紹了
动态游标for循环_数据结构系列循环链表
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前面留的一個問題,后文更跟新回答
????單鏈表可以表示任意的線性關系,有些線性關系是循環的,既沒有隊尾元素。
????將單鏈表中的終端結點指針端由空指針改為指向頭結點,這時的單鏈表形成國恒一個環,改為循環鏈表。
????插入與刪除與單鏈表的原理甚至一模一樣,工程CircleListPro,將單鏈表改成循環鏈表。
CircleList.h文件
ifndef _CIRCLELIST_H_#define?_CIRCLELIST_H_typedef void CircleList;typedef struct _tag_CircleListNode CircleListNote;struct _tag_CircleListNode{ CircleListNode* next; }CircleList* CircleList_Creat(int capacity);void CircleList_Destory(CircleList* list);void CircleList_Clear(CircleList* list);int?CircleList_Length(CircleList*?list);int CircleList_Insert(CircleList* list,CircleListNode* node,int pos);CircleListNode* CircleList_Get(CircleList* list,int pos);CircleListNode* CircleList_Delete(CircleList* list,int pos);#endifCiecleList.c
#include #include #include "CircleList.h"#define AVAILABLE -1//空閑位置的宏//靜態鏈表結構體定義typedef struct _tag_CircleList{ CircleListNode header;//鏈表頭 int length;}TCircleList; CircleList*?CircleList_Create()//o(1){??TCircleList*?ret?=?(TCircleList*)malloc(sizeof(TCircleList));?? if(ret != NULL)//指針不為0時可以繼續賦值操作 { ??ret->length?=?0; ret->header.next = NULL;????} return ret;}void CircleList_Destory(CircleList* list){ free(list);}void CircleList_Clear(CircleList* list) //o(1){ TCircleList* sList = (TCircleList*)list;//用到了數據封裝,所以強制類型轉換 ? if(sList != NULL)//鏈表不為空是合法的,可以繼續清空操作 { sList->length = 0; sList->header.next = NULL;//第一個元素下標沒有了????}}int CircleList_Length(CircleList* list)//o(1){ TCircleList* sList = (TCircleList*)list;//用到了數據封裝,所以強制類型轉換 int ret = -1;//定義一個返回值 if(sList !=NULL)//鏈表不為空是合法的,可以繼續清空操作 { ret = sList->length; } return ret;}//?插入時,如果表頭是空的指向NULL,元素是空的,進行單鏈表元素插入時,現將插入元素// 尾結點與NULL相連,再把插入元素數據與前結點相連,再把該節點next與自己相連,去除原來NULL,構成循環鏈表int?CircleList_Insert(CircleList*?list,CircleListNode*?node,int?pos)//o(n)n是插入元素的位置·{ TCircleList* sList = (TCircleList*)list;//用到了數據封裝,所以強制類型轉換 ??int?ret?=(sList?!=NULL)&& (pos?>=0)?&& (node?!= NULL);//單鏈表方法完成判斷 int i=0; if(ret)//在數組中找空閑位置index {??CircleListNode*?current?= (CircleListNode*)sList;????for(i?=?0;(inext != NULL);?i++) { current = current->next; } ??node->next = current->next;??current->next = node;????if(sList->length?==?0)//?插入的元素是第一個,length的值為0??{?? node->next = node;// 新元素node的next指針指向自己??}????sList->length++ ;}return ret;}CircleListNode* CircleList_Get(CircleList* list,int pos)// o(n){TCircleList* sList = (TCircleList*)list;//用到了數據封裝,所以強制類型轉換 CircleListNode*?ret?=?NULL;//定義一個返回值int i = 0;if((sList?!=?NULL)?&&(0?<=?pos)//鏈表不為空是合法的,長度正常,與單鏈表不同的是不需要pos { CircleListNode*?current?=?(CircleListNode*)sList; for(i=0;i { current = current->next;//第一個元素所在下標 } ret = current->next; }return ret;}//獲取第pos個元素,將第pos個元素從鏈表里刪除//特殊的刪除第一個元素,除了將表頭next移到第二個元素之外,還要將最后一個next移到第二個nextCircleListNode*?CircleList_Delete(CircleList*?list,int?pos)//o(n){ TCircleList* sList = (TCircleList*)list;//用到了數據封裝,所以強制類型轉換 CircleListNode*?ret?=?NULL;//定義一個返回值 int i = 0; if(?(sList?!=NULL)?&& (0?<=?pos)?)//鏈表不為空是合法的,長度正常 { CircleListNode*?current?=?(CircleListNode*)sList;????CircleListNode*?first?=?sList->header.next;//?標記第一個元素 CircleListNode*?last?=?(CircleListNode*)CircleList_Get(sList,sList->length - 1); // 由get函數得到最后一個元素 for(i=0;i { current = current->next;//第一個元素所在下標 } ret = current->next; current->next?=?ret->next; sList->length--; ????if(first?==?ret)//?判斷刪除元素是否是原來表頭,first指針與原來ret指針是否是同一個 { ????sList->header.next?=?ret->next;// 將表頭指向ret????????last->next?=?ret->next;//?指針移動到原來的第二個元素 } ??????if(sList->length?==?0)//?如果鏈表空了則前面操作沒有意義??????{?????? sList->header.next = NULL;// 復原??????} } return ret;}main.c
#include #include #include??"CircleList.h"//自己創建的文件,而不是系統文件用雙引號struct?Value{??CircleListNode?header;//?定義域 int v;// 真正保存數據的域}int main(int argc,char *argv[]){ int i = 0; CircleList*??list?=?CircleList_Create(); struct Value v1; struct Value v2; struct Value v3; struct Value v4; struct Value v5; struct Value v6; struct Value v7; struct Value 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,5);??CircleList_Delete(list,0); ?// 證明是循環鏈表,刪除第一個元素,循環兩遍 ??for(i=0;i?2*CircleList_Length( ??{ ????struct?Value*?pv?=?(struct?Value*)?CircleList_Get(list,i) ????printf("%d\n",pv->v); ??}????printf("\n");????while( CircleList_Length(list) > 0)// 循環鏈表還有元素從頭開始刪????{ ????struct Value* pv = (struct Value*) CircleList_Delete(list,0); ????printf("%d\n",pv->v); } CircleList_Destory(list); return 0;}????為了體現循環鏈表的威力,引入游標:在循環鏈表中定義一個“當前”指針,這個指針通常稱為游標,可以通過這個游標來遍歷鏈表中所有元素。
加了游標新操作CircleList.h文件
#ifndef _CIRCLELIST_H_#define?_CIRCLELIST_H_typedef void CircleList;typedef struct _tag_CircleListNode CircleListNote;struct _tag_CircleListNode{ CircleListNode* next; }CircleList* CircleList_Creat(int capacity);void CircleList_Destory(CircleList* list);void CircleList_Clear(CircleList* list);int?CircleList_Length(CircleList*?list);int CircleList_Insert(CircleList* list,CircleListNode* node,int pos);CircleListNode* CircleList_Get(CircleList* list,int pos);CircleListNode* CircleList_Delete(CircleList* list,int pos);//?加入游標新操作//?獲取當前游標指向的數據元素,可以刪除鏈表里某個數據元素,不需要先得到所要刪除的數據下標CircleListNode* CircleList_DeleteNode(CircleList* list,CircleListNode* node);//?將游標重置指向鏈表中的第一個元素CircleListNode*?CircleList_Resert(CircleList*?list);// 將游標移動到鏈表的下一個數據元素CircleListNode*?CircleList_Current(CircleList*?list);// 直接刪除鏈表中某個數據元素CircleListNode* CircleList_Next(CircleList* list);#endif#include #include #include "CircleList.h"#define AVAILABLE -1//空閑位置的宏//靜態鏈表結構體定義typedef struct _tag_CircleList{ CircleListNode header;//鏈表頭??CircleListNode*?sLidrer;// 定義游標 int length;}TCircleList; CircleList* CircleList_Create()//o(1){ TCircleList* ret = (TCircleList*)malloc(sizeof(TCircleList)); if(ret != NULL)//指針不為0時可以繼續賦值操作 { ret->length = 0; ret->header.next = NULL; ret->slider = NULL;// 在循環鏈表創建的時候,沒有元素,游標定義為空 } return ret;}void CircleList_Destory(CircleList* list){ free(list);}void CircleList_Clear(CircleList* list) //o(1){ TCircleList* sList = (TCircleList*)list;//用到了數據封裝,所以強制類型轉換 if(sList != NULL)//鏈表不為空是合法的,可以繼續清空操作 { sList->length = 0; sList->header.next = NULL;//第一個元素下標沒有了??????sList->slider??=?NULL;//?循環鏈表重置為復原狀態。游標也重置為空 }}int CircleList_Length(CircleList* list)//o(1){ TCircleList* sList = (TCircleList*)list;//用到了數據封裝,所以強制類型轉換 int ret = -1;//定義一個返回值 if(sList !=NULL)//鏈表不為空是合法的,可以繼續清空操作 { ret = sList->length; } return ret;}// 插入時,如果表頭是空的指向NULL,元素是空的,進行單鏈表元素插入時,現將插入元素// 尾結點與NULL相連,再把插入元素數據與前結點相連,再把該節點next與自己相連,去除原來NULL,構成循環鏈表int CircleList_Insert(CircleList* list,CircleListNode* node,int pos)//o(n)n是插入元素的位置·{ TCircleList* sList = (TCircleList*)list;//用到了數據封裝,所以強制類型轉換 int ret =(sList !=NULL)&& (pos >=0) && (node != NULL);//單鏈表方法完成判斷 int i=0; if(ret)//在數組中找空閑位置index { CircleListNode* current = (CircleListNode*)sList; for(i = 0;(inext != NULL); i++) { current = current->next; } node->next = current->next; current->next = node; if(sList->length == 0)// 插入的元素是第一個,length的值為0 {????slider->slider = node;//?游標指向插入的第一個結點 node->next = node;// 游標默認初始位置為0,新元素node的next指針指向自己 } sList->length++ ;}return ret;}CircleListNode* CircleList_Get(CircleList* list,int pos)// o(n){ TCircleList* sList = (TCircleList*)list;//用到了數據封裝,所以強制類型轉換 CircleListNode* ret = NULL;//定義一個返回值 int i = 0; if((sList != NULL) &&(0 <= pos)//鏈表不為空是合法的,長度正常,與單鏈表不同的是不需要pos { CircleListNode* current = (CircleListNode*)sList; for(i=0;i { current = current->next;//第一個元素所在下標 } ret = current->next; } return ret;}//獲取第pos個元素,將第pos個元素從鏈表里刪除//特殊的刪除第一個元素,除了將表頭next移到第二個元素之外,還要將最后一個next移到第二個nextCircleListNode* CircleList_Delete(CircleList* list,int pos)//o(n){ TCircleList* sList = (TCircleList*)list;//用到了數據封裝,所以強制類型轉換 CircleListNode* ret = NULL;//定義一個返回值 int i = 0; if( (sList !=NULL) && (0 <= pos) )//鏈表不為空是合法的,長度正常 { CircleListNode* current = (CircleListNode*)sList; CircleListNode* first = sList->header.next;// 標記第一個元素 CircleListNode* last = (CircleListNode*)CircleList_Get(sList,sList->length - 1); // 由get函數得到最后一個元素 for(i=0;i { current = current->next;//第一個元素所在下標 } ret = current->next; current->next = ret->next; sList->length--; if(first == ret)// 判斷刪除元素是否是原來表頭,first指針與原來ret指針是否是同一個 { sList->header.next = ret->next;// 將表頭指向ret last->next = ret->next;// 指針移動到原來的第二個元素 } if(slider->slider == ret)// SLIDER指向的元素和要刪除的元素指針一致 {????????sList->slider?=?ret->next?;//?slider指向ret的下一個元素 } if(sList->length == 0)// 如果鏈表空了則前面操作沒有意義 { sList->header.next = NULL;// 復原????????sList->slider?=?NULL;//?刪除的元素剛好為鏈表最后一個元素,游標復原為空 } } return ret;}//?獲取當前游標指向的數據元素,刪除對應的CircleListNode*?node這個元素o(n0CircleListNode*?CircleList_DeleteNode(CircleList*?list,CircleListNode*?node){// 該做的檢測正常做 TCircleList* sList = (TCircleList*)list;//用到了數據封裝,所以強制類型轉換 CircleListNode* ret = NULL;//定義一個返回值 int i = 0; if (sList != NULL)???{??? CircleListNode* current = (CircleListNode*)sList;// 做移動,查找node在循環鏈表的邏輯位置 for(i=0;ilength;i++) { ??????if(current->next == node) ??????{ ?????? ret =current->next; ?????? break; ??????} ?????? current = current->next; ??????} ???????if(ret?!=?NULL )// 找不到,非法元素 ???????{???????????????circleList_Delete(sList,i);//?i就是所找到的刪除位置,調用delete刪除即可 ???????}?? ?} return ret;}CircleListNode*?CircleList_Resert(CircleList*?list)// o(1)將游標重置指向鏈表中的第一個元素{// 該做的檢測正常做 TCircleList* sList = (TCircleList*)list;//用到了數據封裝,所以強制類型轉換 CircleListNode* ret = NULL;//定義一個返回值 if(sList != NULL ) { ???slist->slider?=?sList->header.next;// slider重置到第一個元素 ???ret = sList->slider?;// 返回判斷重置是否成功???}???return ret;}CircleListNode*?CircleList_Current(CircleList*?list)//? o(1)將游標移動指向到鏈表中的下一個數據元素{// 該做的檢測正常做 TCircleList* sList = (TCircleList*)list;//用到了數據封裝,所以強制類型轉換 CircleListNode* ret = NULL;//定義一個返回值 if(sList != NULL )??{ ret = sList->slider ; } return ret; }CircleListNode*?CircleList_Next(CircleList*?list)// o(1)直接刪除鏈表中的某個數據元素?{//?該做的檢測正常做 TCircleList* sList = (TCircleList*)list;//用到了數據封裝,所以強制類型轉換 CircleListNode* ret = NULL;//定義一個返回值??//?當前游標指向下一個元素????if((sList?!=?NULL?)?&&?(sList->slider != NULL )) { ret = sList->slider ;// 在移動之前把當前值保存作為返回值返回?????sList->slider = ret->next;// 真正移動 } return ret;}循環鏈表的應用:約瑟夫問題
??? n個人圍成一個圓圈,首先從第一個人從1開始報數,報到第m個人,令其出列;然后再從下一個人繼續報數,報到第m個人,再另其出列……如此下去,求其出列順序。?
main.c
#include #include #include??"CircleList.h"//自己創建的文件,而不是系統文件用雙引號struct?Value{??CircleListNode?header;//?定義域 int v;// 真正保存數據的域}int main(int argc,char *argv[]){ int i = 0; CircleList*??list?=?CircleList_Create(); struct Value v1; struct Value v2; struct Value v3; struct Value v4; struct Value v5; struct Value v6; struct Value v7; struct Value 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,5);??CircleList_Delete(list,0); ?// 證明是循環鏈表,刪除第一個元素,循環兩遍 ??for(i=0;i?2*CircleList_Length( ??{ ????struct?Value*?pv?=?(struct?Value*)?CircleList_Get(list,i) ????printf("%d\n",pv->v); ??}????printf("\n");????while( CircleList_Length(list) > 0)// 循環鏈表還有元素從頭開始刪????{ ????struct Value* pv = (struct Value*) CircleList_Delete(list,0); ????printf("%d\n",pv->v); } printf("\n"); 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++)// 查看八個人是否在循環鏈表中 { ??????struct?Value*?pv?=?(struct?Value*)?CircleList_Next(list) ??????//?先將當前的返回再移動 printf("%d\n",pv->v); } printf("\n"); CircleList_Resert(list); // 重置游標 // 解決約瑟夫問題 ?????while(?CircleList_Length(list)?>?0)//?當鏈表中沒有元素的時候停止出列 { ???struct Value* pv = NULL; ???for(i = 1;i < 3;i++) ???{?????????????CircleList_Next?(list);//?這里的移動用游標來移動,所以很高效 ???} ??pv = (struct Value*) CircleList_Current(list); ??printf("%d\n",pv->v); ???CircleList_DeleteNode(list,(CircleListNode*) pv ); } CircleList_Destory(list); return 0;}小結;
循環鏈表只是在單鏈表的基礎上做了一個加強
循環鏈表完全可以代替單鏈表
循環鏈表的Next和Current操作可以高效的遍歷鏈表中的每個元素
總結
以上是生活随笔為你收集整理的动态游标for循环_数据结构系列循环链表的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 谷歌tts android手机自带引擎,
- 下一篇: solaris php,针对 Solar