单链表实现就地逆转
2015-11-30 21:41
459 查看
在这里,我将展示用头插法的方法实现链表的就地逆转。原理是对于一个给定的链表,先将其头结点摘出来,接下来,依次将链表中的结点摘出来,用头插法插入到摘出来的头结点之后,直到将所有的结点都插入,那么就实现了链表的就地逆转。下面给的程序是c语言程序,可以在gcc里面运行出来。并且有详细的注释,因而在这儿就不再赘述类,看下面的程序。
注意:a.txt文件中的内容就是我们要逆转的数据,要跟我们的.c文件放在一起,否则就要将路径完整写出!!!
注意:a.txt文件中的内容就是我们要逆转的数据,要跟我们的.c文件放在一起,否则就要将路径完整写出!!!
#include <stdio.h> #include <stdlib.h> //===================================================== //操作状态 #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 //===================================================== // 操作状态类型 typedef int Status; // 数据元素类型 typedef int ElemType; //===================================================== // 结点类型 typedef struct tag_LNode{ int data; struct tag_LNode *next; }LNode; //===================================================== // 链表类型(带头结点的单链表) typedef struct { int lenth; // 指示链表长度 LNode *head; // 分别指向头结点和最后一个结点的指针 LNode *current; // 指向当前被访问的结点的指针,初始位置指向头结点 } LinkList; //===================================================== //构造一个空的线性表L Status InitList(LinkList *L) { L->head = (LNode *)malloc(sizeof(LNode));//开辟一个新的空间 if(!L->head) return ERROR; //空间开辟不成功 L->head->next = NULL; //初始化线性表L L->lenth = 0; L->current = L->head; return OK; } //===================================================== //销毁线性表L void DestroyList(LinkList *L) //销毁线性表 L { LNode *p; p = L->head; //p指向表头 while(p) //依次从表头开始删除每一个结点 { L->head = L->head->next;//摘出p free(p); //删除p p = L->head; //又将p指向表头 } } //===================================================== //清空线性表的元素 void ClearList(LinkList *L) { LNode *p; while(L->head->next) //删除除了表头的所有结点 { p = L->head->next; //p指向表头的下一个结点 L->head->next = p->next;//摘出结点p free(p); //删除p } } //===================================================== // 改变当前指针指向第i个结点 Status LocatePos(LinkList *L, int i ) { int k; k = 0; L->current = L->head; //初始化当前指针指向头指针处 while(L->current->next && k < i)//移动当前指针,直到指向第i个位置结束 { L->current = L->current->next; k++; } if(k != i) return ERROR; return OK; } //===================================================== //在当前位置之后插入数据元素e Status InsertAfter(LinkList *L, ElemType e) { LNode *s; if(!L->current) return ERROR;//当前指针为空,就返回错误 s = (LNode *)malloc(sizeof(LNode));//给s开辟新空间 if(!s) return ERROR; //s开辟空间失败 s->data = e; //将e赋给s->data if(L->current->next == NULL)//如果当前指针是最后一个,那么直接插入到最后即可 L->current->next = s; else //当前指针不在最后时,我们就在当前指针之后插入 { s->next = L->current->next; L->current->next = s; } L->lenth++; //插入一个结点后,表的长度要加1 return OK; } //===================================================== //在表头插入数据元素e Status InsertHead(LinkList *L, ElemType e) { LNode *p; p = (LNode *)malloc(sizeof(LNode));//给p开辟新空间 if(!p) return ERROR; //p开辟空间失败 p->data = e; //将e赋给p->data p->next = NULL; p->next = L->head->next; //在表头插入结点p L->head->next = p; L->lenth++; return OK; } //===================================================== //输出单链表的数据 void PrintOut(LinkList L) { LNode *p; printf("链表有%d个元素:",L.lenth); p = L.head->next; while(p) //当p非空时,输出p的数据值 { printf("%d ", p->data); p = p->next; } } //===================================================== //在表中查找数据元素e,让当前指针(current)指向该结点 Status LocateElem(LinkList *L, ElemType e) { LNode *p; p = L->head->next; while(p) { if(p->data == e) //依次判定该结点的数据是不是e { L->current = p; //将当前指针指向p return OK; } p = p->next; } return ERROR; } //===================================================== //求线性表的长度 int ListLenth(LinkList L) { return L.lenth; //直接返回线性表L的长度即可 } //===================================================== //线性表就地逆转(前插法) void ListReverse(LinkList *L) { LNode *p,*q; p = L->head->next; //p指向表头的下一个结点 L->head->next = NULL; //摘出表头 while(p) //依次用前插法插入结点 { q = p->next; //q指向p的下一个结点,将p摘出来 p->next = L->head->next;//将摘出来的p出入到表头的后面 L->head->next = p; p = q; //将p指向q指向的位置 } } //===================================================== int main(int argc,char* argv) { FILE *fp; //文件指针 LinkList L; //线性表 ElemType e; int j; //j作为后面选项的变量 int i = 1; //i作为while循环的判定变量 if((fp = fopen("a.txt", "r")) == 0)//打开文件“a.txt”,r表示可读的意思 { printf("打开文件失败"); return -1; } if(!InitList(&L)) //初始化链表L { printf("初始化链表失败\n"); return -2; } LocatePos(&L, 0); //改变当前指针指向表的头结点 while(1) //读入数据并插入到表中 { if(fscanf(fp, "%d", &e) == EOF)//文件中的数据读数据到单链表L,知道读到文件最后,再跳出while循环,EOF是end of file 的意思 break; InsertAfter(&L, e); } while(i) { printf("1.查看原始链表中的数据\n"); printf("2.输出链表长度\n"); printf("3.查找链表中的元素\n"); printf("4.逆转该链表,并输出逆转后的数据\n"); printf("5.销毁链表\n"); printf("0.退出!\n"); printf("选择你要进行的操作\n"); scanf("%d", &j); //输入选项 printf("\n"); switch(j) //使用了switch-case来对选择不同的选项进行不同的操作 { case 1: //输出单链表L的数据 printf("\n原始链表\n"); PrintOut(L); //输出原始链表中的数据 printf("\n\n"); break; case 2: //链表长度 printf("链表长度:%d\n", ListLenth(L));//调用了链表长度的函数 printf("\n"); break; case 3: //查找链表元素 printf("输入要查找的数: "); scanf("%d", &e); if(LocateElem(&L, e))//LocateElem(&L,e)是调用定位函数,将当前指针定位到元素e的位置 printf("元素%d在链表中\n", L.current->data); else printf("元素%d不在链表中\n", e); printf("\n"); break; case 4: //链表就地逆转 printf("\n原始链表\n"); PrintOut(L); //输出原始链表里面的元素 printf("\n\n"); ListReverse(&L);//调用逆转链表的函数 printf("\n逆转链表\n"); PrintOut(L); printf("\n\n"); break; case 5: //销毁链表L DestroyList(&L);//调用销毁链表的函数 printf("\n"); break; case 0: printf("\n结束!\n"); i = 0; //i = 0使得跳出整个while循环,结束程序 printf("\n"); } } return 0; }
相关文章推荐
- 如何组织构建多文件 C 语言程序(二)
- 如何写好 C main 函数
- Lua和C语言的交互详解
- C#定义并实现单链表实例解析
- C#数据结构之单链表(LinkList)实例详解
- 关于C语言中参数的传值问题
- 简要对比C语言中三个用于退出进程的函数
- 深入C++中API的问题详解
- 基于C语言string函数的详解
- C语言中fchdir()函数和rewinddir()函数的使用详解
- C语言内存对齐实例详解
- C语言编程中统计输入的行数以及单词个数的方法
- 使用C语言判断英文字符大小写的方法
- c语言实现的带通配符匹配算法
- C语言实现顺序表基本操作汇总
- C语言中计算正弦的相关函数总结
- 使用C语言详解霍夫曼树数据结构
- 探讨C语言的那些小秘密之断言
- C语言实现BMP转换JPG的方法
- 深入探讨C语言中局部变量与全局变量在内存中的存放位置