单链表实现就地逆转

在这里,我将展示用头插法的方法实现链表的就地逆转。原理是对于一个给定的链表,先将其头结点摘出来,接下来,依次将链表中的结点摘出来,用头插法插入到摘出来的头结点之后,直到将所有的结点都插入,那么就实现了链表的就地逆转。下面给的程序是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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值