【数据结构】单向链表,单向循环链表,双向循环链表
单向链表
头文件
1 //@ author 成鹏致远 2 //@ net http://infodown.tap.cn 3 //@ qq 552158509 4 //@ blog lcw.cnblogs.com 5 6 #ifndef _LINKLIST_H 7 #define _LINKLIST_H 8 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <stdbool.h> 12 13 typedef int datatype; 14 15 typedef struct node 16 { 17 datatype data; 18 struct node *next; 19 }linklist,*plinklist; 20 21 extern void linklist_init(plinklist *plist);//初始化链表 22 extern void linklist_create(plinklist plist, int len);//从头结点创建链表 23 extern void linklist_create_tail(plinklist plist, int len);//从链表尾创建链表 24 extern void linklist_sort(plinklist plist);//实现链表的逆转 25 extern void linklist_show(plinklist plist);//显示链表 26 27 #endif
单向链表
1 //@ author 成鹏致远 2 //@ net http://infodown.tap.cn 3 //@ qq 552158509 4 //@ blog lcw.cnblogs.com 5 6 #include "linklist.h" 7 8 void linklist_init(plinklist *plist)//初始化链表 9 { 10 *plist = (plinklist)malloc(sizeof(linklist));//申请空间 11 if(*plist == NULL) 12 { 13 perror("malloc"); 14 exit(1); 15 } 16 (*plist)->next = NULL;//初始化为空 17 } 18 19 void linklist_create(plinklist plist, int len)//从头结点创建链表 20 { 21 plinklist new; 22 23 while(len--)//创建len个结点 24 { 25 new = (plinklist)malloc(sizeof(linklist));//申请新空间 26 if(new == NULL) 27 { 28 perror("malloc"); 29 exit(1); 30 } 31 new->data = len+1;//完成新结点的赋值 32 33 //现在需要将新申请的结点和已有的结点链接在一起 34 //注意是在头部插入 35 new->next = plist->next;//将新申请的new结点插入到链表的最前面 36 plist->next = new; 37 } 38 } 39 40 void linklist_create_tail(plinklist plist, int len)//从链表尾创建链表 41 { 42 plinklist new; 43 plinklist tail = plist;//tail表示链表的最后一个结点,在整个过程中,必须保证头结点(plist)的值不变 44 int i; 45 46 for(i=0; i<len; i++) 47 { 48 new = (plinklist)malloc(sizeof(linklist));//申请新空间 49 if(new == NULL) 50 { 51 perror("malloc"); 52 exit(1); 53 } 54 new->data = i+1; 55 56 //现在需要将新申请的结点和已有的结点链接在一起 57 //注意是在尾部插入 58 new->next = tail->next;//tail->next为空,new将成为新的尾结点 59 tail->next = new;//将new结点插入到tail的后面 60 tail = new;//tail后移,new成为新的尾结点 61 62 } 63 } 64 65 void linklist_sort(plinklist plist)//实现链表的逆转 66 { 67 //思想 68 //在创建时把最早申请的结点放到了最后面,最后申请的结点放到了最前面 69 //所以逆转的过程就相当于创建时过程的重复执行,把最前面的又放到最后面 70 //逆转过程和入栈|出栈是一样的 71 //出栈|入栈只是为了方便理解 72 73 plinklist p = plist->next;//所有的操作必须保证头结点不变,用p指向链表的第一个元素,负责逆转过程中原链表的的移位 74 plinklist tem = NULL;//临时变量,负责将原链表元素转移到逆转后的链表(相当于:出栈后入栈) 75 76 plist->next = NULL;//切断头结点与原链表的联系,以便重新建立链表 77 78 while(p != NULL)//p辅助移位,相当于依次出栈 79 { 80 tem = p;//标记出栈的元素,即将入栈 81 p = p->next;//移位,依次出栈 82 83 //将出栈的元素加入到逆转后的链表,相当于再次入栈 84 //插入过程和从头部创建链表过程一样 85 tem->next = plist->next; 86 plist->next = tem;//tem作为链表的第一个元素 87 88 } 89 } 90 91 void linklist_show(plinklist plist)//显示链表 92 { 93 plinklist tem = plist->next;//同样是为了不改变头结点,所以需要临时结点指针 94 95 while(tem != NULL) 96 { 97 printf("%d\t",tem->data); 98 tem = tem->next; 99 } 100 printf("\n"); 101 }
主文件
1 //@ author 成鹏致远 2 //@ net http://infodown.tap.cn 3 //@ qq 552158509 4 //@ blog lcw.cnblogs.com 5 6 //用单向链表实现数据逆转 7 //首先建立一个包含若干整数的单向链表,然后实现逆转 8 9 #include "linklist.h" 10 11 int main() 12 { 13 plinklist plist; 14 int length; 15 16 linklist_init(&plist);//完成初始化_ 17 18 printf("Pls input the length of linklist:"); 19 scanf("%d",&length); 20 #if 0 21 linklist_create(plist,length);//从头结点创建链表 22 linklist_show(plist);//显示链表 23 linklist_sort(plist);//逆转链表 24 linklist_show(plist); 25 26 #else 27 printf("******************************************\n"); 28 linklist_create_tail(plist,length);//从尾结点创建链表 29 linklist_show(plist);//显示链表 30 linklist_sort(plist);//逆转链表 31 linklist_show(plist); 32 33 #endif 34 35 return 0; 36 }
单向循环链表(josephu问题)
头文件
1 //@ author 成鹏致远 2 //@ net http://infodown.tap.cn 3 //@ qq 552158509 4 //@ blog lcw.cnblogs.com 5 6 #ifndef _LINKLIST_H 7 #define _LINKLIST_H 8 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <stdbool.h> 12 13 typedef int datatype; 14 15 typedef struct node 16 { 17 datatype data; 18 struct node *next; 19 }linklist,*plinklist; 20 21 22 extern void josephu_init(plinklist *plist);//完成初始化 23 extern void josephu_create(plinklist *plist, int len);//创建链表 24 extern datatype josephu(plinklist plist);//完成数3出局 25 extern void josephu_show(plinklist plist);//显示链表 26 27 28 #endif
josephu
1 //@ author 成鹏致远 2 //@ net http://infodown.tap.cn 3 //@ qq 552158509 4 //@ blog lcw.cnblogs.com 5 6 //用单向循环链表现实"数3出局"游戏(Josephu问题) 7 //首先建立一个包含若干整数的单向循环链表,然后从第一个节点开始数,把数到3的那个节点删除 8 //接着下一个节点开始数,数到3继续删除,以此类推,打印出最后剩余的那个节点 9 10 #include "linklist.h" 11 12 void josephu_init(plinklist *plist)//完成初始化 13 { 14 #if 1//无头结点的初始化 15 *plist = NULL; 16 #else//有头结点的初始化 17 *plist = (plinklist)malloc(sizeof(linklist)); 18 if(*plist == NULL) 19 { 20 perror("malloc"); 21 exit(1); 22 } 23 (*plist)->next = *plist; 24 #endif 25 } 26 27 void josephu_create(plinklist *plist, int len)//创建链表,因为初始化时没有头结点,所以参数需要传*plist 28 { 29 plinklist new; 30 plinklist tail;//尾指针,从链表尾部插入新结点 31 int i; 32 33 for(i=0; i<len; i++) 34 { 35 if(0 == i)//因为无头结点,所以第一次也需要申请空间,并指向自己 36 { 37 *plist = (plinklist)malloc(sizeof(linklist)); 38 if(*plist == NULL) 39 { 40 perror("malloc"); 41 exit(1); 42 } 43 (*plist)->data = i+1; 44 (*plist)->next = *plist;//只有一个结点,指向自己 45 46 tail = *plist;//初始化尾指针 47 } 48 else 49 { 50 new = (plinklist)malloc(sizeof(linklist)); 51 if(new == NULL) 52 { 53 perror("malloc"); 54 exit(1); 55 } 56 new->data = i+1; 57 //将新结点new和已有结点连在一起 58 //注意是在尾部插入 59 new->next = tail->next; 60 tail->next = new;//将new结点插入到tail后面 61 tail = new;//new变成新的尾结点 62 } 63 } 64 } 65 66 datatype josephu(plinklist plist)//完成数3出局 67 { 68 plinklist head = plist;//指向每次变化的"头结点",每出局一个人,下一个人将变成头结点 69 plinklist tem;//临时指针,指向每次出局的人 70 71 while(head != head->next)//只剩下一人时退出循环 72 { 73 tem = head->next->next;//tem将出局 74 head->next->next = tem->next;//tem->next将是下一个"头结点" 75 head = tem->next;//新"头结点" 76 77 printf("%d\t",tem->data); 78 free(tem);//tem出局 79 } 80 return head->data; 81 } 82 83 void josephu_show(plinklist plist)//显示链表 84 { 85 plinklist tem = plist;//保证头结点不变 86 while(tem != NULL && tem->next != plist)//循环遍历 87 { 88 printf("%d\t",tem->data); 89 tem = tem->next; 90 } 91 //注意最后一次循环是tem->next = plist,所以最后一个结点并没有输出 92 printf("%d\n",tem->data); 93 94 }
主文件
1 //@ author 成鹏致远 2 //@ net http://infodown.tap.cn 3 //@ qq 552158509 4 //@ blog lcw.cnblogs.com 5 6 //用单向循环链表现实"数3出局"游戏(Josephu问题) 7 //首先建立一个包含若干整数的单向循环链表,然后从第一个节点开始数,把数到3的那个节点删除 8 //接着下一个节点开始数,数到3继续删除,以此类推,打印出最后剩余的那个节点 9 10 #include "linklist.h" 11 12 int main() 13 { 14 plinklist plist; 15 datatype result; 16 int len; 17 18 josephu_init(&plist);//完成初始化 19 20 printf("Pls input the length of josephu:"); 21 scanf("%d",&len); 22 23 josephu_create(&plist,len);//创建josephu链表 24 josephu_show(plist);//显示josephu链表 25 26 result = josephu(plist);//解决方案 27 printf("\nThe last is %d\n",result); 28 29 return 0; 30 }
双向循环链表
头文件
1 //@ author 成鹏致远 2 //@ net http://infodown.tap.cn 3 //@ qq 552158509 4 //@ blog lcw.cnblogs.com 5 6 #ifndef _DOUBLELIST_H 7 #define _DOUBLELIST_H 8 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <stdbool.h> 12 13 typedef int datatype; 14 15 typedef struct node 16 { 17 datatype data; 18 struct node *next,*prior; 19 }double_list,*double_plist; 20 21 extern void double_init(double_plist *plist);//双向链表的初始化 22 extern void double_sort(double_plist plist);//完成双向链表的奇数升序偶数降序排列 23 extern void double_create(double_plist plist, int len);//头插法创建双向链表 24 extern void double_show(double_plist plist);//显示双向链表 25 26 #endif
双向循环链表
1 //@ author 成鹏致远 2 //@ net http://infodown.tap.cn 3 //@ qq 552158509 4 //@ blog lcw.cnblogs.com 5 6 //用双向循环链表实现顺序递增存储若干个自然数 7 //比如输入一个整数10,则建立一个双向循环链表,里面的每个节点分别存放1,2,3,4,5,6,7,8,9,10 8 //然后通过某些操作,将其重新排列成1,3,5,7,9,10,8,6,4,2,即奇数升序偶数降序,并在屏幕上打印出来 9 10 #include "double_list.h" 11 12 void double_init(double_plist *plist)//双向链表的初始化 13 { 14 *plist = (double_plist)malloc(sizeof(double_list)); 15 if(*plist == NULL) 16 { 17 perror("malloc"); 18 exit(1); 19 } 20 21 (*plist)->next = (*plist)->prior = *plist;//双向链表的前后指针都指向自己 22 23 } 24 25 void double_sort(double_plist plist)//完成双向链表的奇数升序偶数降序排列 26 { 27 double_plist pnext = plist->next;//指向链表的第一个节点 28 double_plist prior = plist->prior;//指向链表的最后一个节点 29 double_plist tem = NULL;//临时指针,用于辅助定位将被移动的节点 30 31 while(pnext != prior)//没有到达链表尾 32 { 33 if(pnext->data%2 !=0)//为奇数,直接跳过 34 pnext = pnext->next; 35 else//为偶数,将pnext移动到偶数后面一位奇数位置,用tem指向回去辅助移动偶数链表节点 36 { 37 pnext = pnext->next; 38 39 //将pnext前面的节点剪切出来 40 tem = pnext->prior;//tem指向要被移动的节点 41 pnext->prior = tem->prior;//将奇数节点前向指针连接起来 42 tem->prior->next = pnext;//将奇数节点后向指针连接起来 43 44 //将偶数节点(tem)插入到链表尾(prior) 45 tem->next = prior->next;//tem将成为新的尾结点 46 prior->next->prior = tem;//链表首尾相连 47 //prior和新的尾结点tem相连 48 tem->prior = prior; 49 prior->next = tem; 50 } 51 } 52 } 53 54 void double_create(double_plist plist, int len)//头插法创建双向链表 55 { 56 double_plist new; 57 while(len--)//创建len个节点 58 { 59 new = (double_plist)malloc(sizeof(double_list)); 60 if(new == NULL) 61 { 62 perror("malloc"); 63 exit(1); 64 } 65 new->data = len+1; 66 67 //向plist后面插入一个新的节点 68 //双向链表的头插法 69 new->next = plist->next; 70 plist->next->prior = new; 71 new->prior = plist; 72 plist->next = new; 73 } 74 } 75 76 void double_show(double_plist plist)//显示双向链表 77 { 78 double_plist tem = plist->next;//保证头结点不变 79 80 while(tem != plist)//遍历一个循环 81 { 82 printf("%d\t",tem->data); 83 tem = tem->next; 84 } 85 printf("\n"); 86 }
主文件
1 //@ author 成鹏致远 2 //@ net http://infodown.tap.cn 3 //@ qq 552158509 4 //@ blog lcw.cnblogs.com 5 6 //用双向循环链表实现顺序递增存储若干个自然数 7 //比如输入一个整数10,则建立一个双向循环链表,里面的每个节点分别存放1,2,3,4,5,6,7,8,9,10 8 //然后通过某些操作,将其重新排列成1,3,5,7,9,10,8,6,4,2,即奇数升序偶数降序,并在屏幕上打印出来 9 10 #include "double_list.h" 11 12 int main() 13 { 14 double_plist plist; 15 int len; 16 17 double_init(&plist);//双向链表初始化 18 19 printf("Pls input the length of double list:"); 20 scanf("%d",&len); 21 22 double_create(plist,len);//创建双向链表 23 double_show(plist);//显示双向链表 24 25 double_sort(plist);//完成奇数升序偶数降序排序 26 double_show(plist); 27 28 return 0; 29 }