您的位置:首页 > 编程语言 > C语言/C++

单链表实现就地逆转

2015-11-30 21:41 459 查看
在这里,我将展示用头插法的方法实现链表的就地逆转。原理是对于一个给定的链表,先将其头结点摘出来,接下来,依次将链表中的结点摘出来,用头插法插入到摘出来的头结点之后,直到将所有的结点都插入,那么就实现了链表的就地逆转。下面给的程序是c语言程序,可以在gcc里面运行出来。并且有详细的注释,因而在这儿就不再赘述类,看下面的程序。

注意: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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息