单链表实现就地逆转

来源:互联网 发布:人工智能作业答案 编辑:程序博客网 时间:2024/04/30 12:52

在这里,我将展示用头插法的方法实现链表的就地逆转。原理是对于一个给定的链表,先将其头结点摘出来,接下来,依次将链表中的结点摘出来,用头插法插入到摘出来的头结点之后,直到将所有的结点都插入,那么就实现了链表的就地逆转。下面给的程序是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;//=====================================================//构造一个空的线性表LStatus 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;}//=====================================================//销毁线性表Lvoid 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;}//=====================================================//在当前位置之后插入数据元素eStatus 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;}//=====================================================//在表头插入数据元素eStatus 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;}

1 0
原创粉丝点击