利用头插法实现逆置

下面简单介绍一下,算法思想结合图示看

算法思想:“删除”头结点与链表其他结点的原有联系(即将头结点的指针置空),再逐个插入逆置链表的表头(即“头插”到逆置链表中),使它成为逆置链表的“新”的头结点,如此循环,直至原链表为空。

这是鬼话,看不懂可以不看,看下面就行......

void NiList(LinkList &L)    //逆置
{
LinkList p = L->next, q; //L->next是头结点的指针,p指针指向了首结点
L->next = NULL; //将头结点的指针置空
while (p != NULL)
{
q = p; //指针q从指向第一个结点开始后移
p = p->next; //指针p从指向第二个结点开始后移
q->next = L->next; //指针q所指向结点的指针q->next指向其上一个结点
L->next = q; //头结点的指针后移
}
}

接下来,进行图解:

刚开始是这样

L->next是头结点指针。循环前的操作,p指向首结点(即第一个结点),头结点的指针置空

进入循环,q和p分别指向第一个和第二个节点

q所指向结点的指针q->next指向其(q->next)上一个结点,这里上一个结点的指针为空,故q->next也为空

L->next = q;    //头指针后移,指向首结点
 

进入第二轮循环,这是发生重大变化的关键时期

q和p继续后移,这个图有点错误懒得改了,就是后移后,指针q指向了b结点,指针p指向了c结点

q所指向结点的指针q->next指向其上一个结点

头指针后移,指向第二个结点

你可以看到此时已经开始逆置,如此循环, 直到p==NULL为空

链表完整代码:

1):从键盘输入生成链表

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h> #define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define TRUE 1
#define FALSE 0 typedef int Status;
typedef int ElemType;
typedef struct LNode
{
ElemType data;
struct LNode* next;
}LNode,*LinkList;
/*定义了两种新的数据类型LNode和LinkList,显然各个结点是LNode类型的,
头指针和结点的next成员是LinkList类型的,L是LinkList这个新的结构体指针类型定义的头指针*/ Status InitList(LinkList &L) //初始化
{
L = (LinkList)malloc(sizeof(LNode));
if (L == NULL)return ERROR;
L->next = NULL;
return OK;
} Status ListEmpty(LinkList L) //判空
{
if (L->next == NULL) return TRUE;
return FALSE;
} Status ListInsert(LinkList &L, int i, ElemType e) //插入
{
int j = 0;
LinkList p = L, s; //指针p指向头指针
if (i<1) return ERROR;
while ((p != NULL) && (j<i - 1))
{
p = p->next;
j++;
}
if(p==NULL)return ERROR;
s = (LNode*)malloc(sizeof(LNode)); //生成新节点
if (s == NULL) return ERROR;
s->data = e; //s结点暂存e
s->next = p->next; //s结点的指针s->next指向第i个结点
p->next = s; //第i-1个结点的指针p->next指向s结点
return OK;
} Status ScanfList(LinkList &L) //键盘输入
{
ElemType e;
int i = 1;
printf("输入整数,以0结束:\n");
scanf("%d", &e);
while (e != 0)
{
if (!ListInsert(L, i, e)) return ERROR;
i++;
scanf("%d", &e);
}
return OK;
} Status ListDelete(LinkList &L, int i, ElemType &e) //删除
{
int j = 0;
LinkList p = L, q;
if ((i<1) || (L->next == NULL)) return ERROR;
while ((p != NULL) && (j<i - 1))
{
p = p->next;
j++;
}
if (p == NULL) return ERROR;
q = p->next; //指针q暂存被删结点(第i个结点)的地址
p->next = q->next; //指针p(即第i-1个结点的指针)指向被删结点(第i+1个结点)
e = q->data;
free(q);
return OK;
} Status GetElem(LinkList L, int i, ElemType &e) //取值
{
int j = 1;
LinkList p = L->next;
if (i<1) return ERROR;
while ((p != NULL) && (j<i))
{
p = p->next;
j++;
}
if (p == NULL) return ERROR;
e = p->data;
return OK;
} int LocateElem(LinkList L, ElemType e) //定位
{
int j = 1;
LinkList p = L->next;
while (p != NULL)
{
if (p->data == e)return j;
p = p->next;
j++;
}
return j;
} Status PriorElem(LinkList L, ElemType e, ElemType &pr_e) //直接前驱
{
LinkList p = L->next;
if (p->data == e) return ERROR; //首结点没有直接前驱
while (p != NULL)
{
if (p->next->data == e) break;
p = p->next;
}
if (p == NULL) return ERROR; //指针p一直移到尾结点仍找不到e,返回错误
pr_e = p->data;
return OK;
} int GetLength(LinkList L) //求长度
{
int i = 0;
LinkList p = L;
while (p->next != NULL)
{
p = p->next;
i++;
}
return i;
} void PrnList(LinkList L) //遍历
{
LinkList p = L->next;
while (p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
printf("\n");
} void NiList(LinkList &L) //逆置
{
LinkList p = L->next, q; //p指针指向了首结点
L->next = NULL; //将头结点的指针置空
while (p != NULL)
{
q = p; //指针q从指向第一个结点开始后移
p = p->next; //指针p从指向第二个结点开始后移
q->next = L->next; //指针q所指向结点的指针q->next指向其上一个结点
L->next = q; //头结点的指针后移
}
} Status Destroy(LinkList &L) //销毁,从首结点开始
{
LinkList p = L->next, q;
while (p != NULL)
{
q = p->next;
free(p);
p = q;
}
free(L);
return OK;
} int main()
{
int i;
ElemType e, e1; LinkList L;
if (InitList(L)) printf("OK\n");
ScanfList(L);
PrnList(L); int k;
printf("\n1.插入\n2:删除\n3:取值\n4:定位\n5:直接前驱\n");
printf("6.求长度\n7:遍历\n8:逆置\n9:销毁\n\n0.退出\n");
scanf("%d", &k);
while (k != 0)
{
switch (k)
{
case 1:
printf("在第几个位置插入何数:");
scanf("%d%d", &i, &e);
if (ListInsert(L, i, e)) printf("OK\n");
break;
case 2:
printf("删除第几个数:");
scanf("%d", &i);
if (ListDelete(L, i, e))printf("删除数为:%d\n", e);
break;
case 3:
printf("获取第几个数:");
scanf("%d", &i);
if (GetElem(L, i, e)) printf("数为:%d\n", e);
break;
case 4:
printf("定位何数:");
scanf("%d", &e);
if (LocateElem(L, e)) printf("位序为:%d\n", LocateElem(L, e));
break;
case 5:
printf("寻找何数直接前驱:");
scanf("%d", &e);
if (PriorElem(L, e, e1)) printf("前驱为:%d\n", e1);
break;
case 6:
printf("表长为:");
printf("%d\n", GetLength(L));
break;
case 7:
printf("遍历:\n");
PrnList(L);
break;
case 8:
NiList(L);
PrnList(L);
printf("逆置成功\n");
break;
case 9:
if (Destroy(L))printf("销毁成功\n");
break;
default:
printf("ERROR\n");
}
scanf("%d", &k);
}
return 0;
}

2):读取数组生成链表

#include<stdio.h>
#include<stdlib.h> #define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define TRUE 1
#define FALSE 0 typedef int Status;
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode, *LinkList;
/*定义了两种新的数据类型LNode和LinkList,显然各个结点是LNode类型的,
头指针和结点的next成员是LinkList类型的,L是LinkList结点指针类型定义的头指针*/ Status InitList(LinkList &L) //初始化
{
L = (LinkList)malloc(sizeof(LNode));
if (L == NULL)return ERROR;
L->next = NULL;
return OK;
} Status ListEmpty(LinkList L) //判空
{
if (L->next == NULL)return ERROR;
else return FALSE;
} Status ListInsert(LinkList &L, int i, ElemType e) //插入
{
int j = 0;
LinkList p = L, s; //指针p指向头指针
if (i < 1)return ERROR;
while (p != NULL && j < i - 1)
{
p = p->next;
j++;
}
if (p == NULL)return ERROR;
s = (LNode*)malloc(sizeof(LNode)); //生成新节点
if (s == NULL)return ERROR;
s->data = e; //结点s暂存e
s->next = p->next; //s结点的指针s->next指向第i个结点
p->next = s; //指针p指向s结点
return OK;
} Status CreateList(LinkList &L,ElemType element[], int n) //数组生成链表
{
int i;
for (i = 0; i < n; i++)
if (!ListInsert(L, i + 1, element[i])) return ERROR;
return OK;
} Status ListDelete(LinkList &L, int i, ElemType &e) //删除
{
int j = 0;
LinkList p = L, q;
if (i < 1 || p->next == NULL)return ERROR;
while (p != NULL && j<i - 1)
{
p = p->next;
j++;
}
if (p == NULL)return ERROR;
q = p->next; //指针q暂存被删结点(第i个结点)的地址,故指针q指向了被删结点
p->next = q->next; //指针p(即第i-1个结点的指针)指向被删结点的下一结点(第i+1个结点)
e = q->data;
free(q);
return OK;
} Status GetElem(LinkList L, int i, ElemType &e) //取值
{
int j = 1;
LinkList p = L->next;
if (i < 1)return ERROR;
while (p != NULL && j<i)
{
p = p->next;
j++;
}
if (p == NULL)return ERROR;
e = p->data;
return OK;
} int LocateElem(LinkList L, ElemType e) //定位
{
int j = 1;
LinkList p = L->next;
while (p != NULL)
{
if (p->data == e)return j;
p = p->next;
j++;
}
return j;
} Status PriorElem(LinkList L, ElemType e, ElemType &pr_e) //直接前驱
{
LinkList p = L->next;
if (p->data==e)return ERROR; //首结点没有直接前驱
while (p != NULL)
{
p = p->next;
if (p->next->data == e)break;
}
if (p == NULL)return ERROR; //指针p一直移到尾结点仍找不到e,返回错误
pr_e = p->data;
return OK;
} int GetLength(LinkList L) //求长度
{
int i = 0;
LinkList p = L;
while (p->next != NULL)
{
p = p->next;
i++;
}
return i;
} void PrnList(LinkList L) //遍历
{
LinkList p = L->next;
while (p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
printf("\n");
} Status NiList(LinkList &L) //逆置
{
LinkList p = L->next, q; //指针p指向了首结点
L->next = NULL; //将头结点指针置空
while (p != NULL)
{
q = p; //指针q从指向第一个结点开始后移
p = p->next; //指针p从指向第二个结点开始后移
q->next = L->next; //指针q所指向结点的指针q->next指向其上一个结点
L->next = q; //头结点的指针后移
}
return OK;
} Status Destroy(LinkList &L) //销毁,从首结点开始
{
LinkList p = L->next, q;
if (p == NULL)return ERROR;
while (p != NULL)
{
q = p->next;
free(p);
p = q;
}
free(L);
return OK;
} int main()
{
int i;
ElemType e, e1; LinkList L;
ElemType element[] = { 15, 3, 59, 27, 8, 11, 32 };
if (InitList(L)) printf("OK\n");
CreateList(L,element,7);
PrnList(L); int k;
printf("\n1.插入\n2:删除\n3:取值\n4:定位\n5:直接前驱\n");
printf("6.求长度\n7:遍历\n8:逆置\n9:销毁\n\n0.退出\n");
scanf("%d", &k);
while (k != 0)
{
switch (k)
{
case 1:
printf("在第几个位置插入何数:");
scanf("%d%d", &i, &e);
if (ListInsert(L, i, e)) printf("OK\n");
break;
case 2:
printf("删除第几个数:");
scanf("%d", &i);
if (ListDelete(L, i, e))printf("删除数为:%d\n", e);
break;
case 3:
printf("获取第几个数:");
scanf("%d", &i);
if (GetElem(L, i, e)) printf("数为:%d\n", e);
break;
case 4:
printf("定位何数:");
scanf("%d", &e);
if (LocateElem(L, e)) printf("位序为:%d\n", LocateElem(L, e));
break;
case 5:
printf("寻找何数直接前驱:");
scanf("%d", &e);
if (PriorElem(L, e, e1)) printf("前驱为:%d\n", e1);
break;
case 6:
printf("表长为:");
printf("%d\n", GetLength(L));
break;
case 7:
printf("遍历:\n");
PrnList(L);
break;
case 8:
NiList(L);
PrnList(L);
printf("逆置成功\n");
break;
case 9:
if (Destroy(L))printf("销毁成功\n");
break;
default:
printf("ERROR\n");
}
scanf("%d", &k);
}
return 0;
}

C语言实现数据机构链表的基本操作(从键盘输入生成链表、读取数组生成链表)的更多相关文章

  1. C语言 投票系统:给定候选人,从键盘输入候选人的名字,统计票数,并输出最终获胜者

    投票系统:给定候选人名单,从键盘输入候选人的名字,统计票数,并输出最终获胜者.若投票人输入的名字不在其候选名单上,则该票数无效. //凯鲁嘎吉 - 博客园 http://www.cnblogs.com ...

  2. 3012C语言_数据

    第二章 数据 2.1 数据类型 2.1.1 数据类型决定 1. 数据占内存字节数 2. 数据取值范围 3. 其上可进行的操作 2.2基本数据类型 2.2.1分类 基本类型 类型 符号 关键字 字节 1 ...

  3. 数据结构算法C语言实现(五)---2.3重新定义线性链表及其基本操作

    一.简述 ...由于链表在空间的合理利用上和插入.删除时不需要移动等的优点,因此在很多场合下,它是线性表的首选存储结构.然而,它也存在着实现某些基本操作,如求线性表的长度时不如顺序存储结构的缺点:另一 ...

  4. C语言链表的基本操作

    */ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.cpp * 作者:常轩 * 微信公众号:Worldhe ...

  5. C++学习笔记48:链表的基本操作

    //链表的基本操作 //生成链表,插入结点,查找结点,删除结点,遍历链表,清空链表 //链表类模板 //LinkedList.h #ifndef LINKEDLIST_H #define LINKED ...

  6. PHP单链表的基本操作

    链表的实现 数据结构第一个就是链表了,链表分为两种有直接的数组形式的顺序链,这里不讨论,什么array_push(),array_pop(),函数基本能满足日常的需求,但报告老板,我就是想装个X 上代 ...

  7. R语言进行数据预处理wranging

    R语言进行数据预处理wranging li_volleyball 2016年3月22日 data wrangling with R packages:tidyr dplyr Ground rules ...

  8. 用Java实现单链表的基本操作

    笔试题中经常遇到单链表的考题,下面用java总结一下单链表的基本操作,包括添加删除节点,以及链表转置. package mars; //单链表添加,删除节点 public class ListNode ...

  9. SQL语言学习-数据定义语言

    Sql语言至今已经有6个版本.SQL查询语言包括了所有对数据的操作命令,这些操作可分为四类:数据定义语言(DDL).数据操纵语言(DML).数据控制语言(DCL)和嵌入式SQL语言. 数据定义语言(D ...

随机推荐

  1. Object中toString方法

    在Java中,所有的对象都是继承自Object,自然继承了toString方法,在当使用System,out.println()里面为一个对象的引用时,自动调用toString方法将对象打印出来.如果 ...

  2. 力扣Leetcode 33. 搜索旋转排序数组

    33. 搜索旋转排序数组 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 搜索一个给定的目标值, ...

  3. PyTorch入门-CIFAR10图像分类

    CIFAR10数据集下载 CIFAR10数据集包含10个类别,图像尺寸为 3×32×32 官方下载地址很慢,这里给一个百度云: https://pan.baidu.com/s/1oTvW8wNa-VO ...

  4. [ASP.NET Core开发实战]开篇词

    前言 本系列课程文章主要是学习官方文档,再输出自己学习心得,希望对你有所帮助. 课程大纲 本系列课程主要分为三个部分:基础篇.实战篇和部署篇. 希望通过本系列课程,能让大家初步掌握使用ASP.NET ...

  5. 数字电路基础(二)TTL与非门输入端悬空和接大电阻的问题

    引言 我们在做那些判断与非门输入输出的时候,常常把输入端悬空和接大电阻作为高电平输入处理,比如下边这一例题: 很显然,我们无法直接从与非门逻辑图中看出其内部工作原理,那我们该如何分析呢?那肯定是去分析 ...

  6. Google Kick Start 2020 Round B T1-3

    这场题目除了最后一题稍微难了点,其他都是1眼题. T1 Bike Tour 没啥好说的,一个循环解决. T2 Bus Routes 没啥好说的,从第\(n\)的车站开始贪心取最晚的. T3 Robot ...

  7. 数据库的表的字段名称与实体类(pojo)不对应解决方案

    数据库的表的字段名称与实体类(pojo)不对应解决方案 数据库表 ![image-20200429130200825](C:%5CUsers%5C%E6%9E%97%E6%AD%A3%E6%98%8E ...

  8. 前端插入date类型的数据到数据库

    //插入 @Override public boolean insertEmp(Emp emp) { String sql = "insert into emp(lwlEmpno,lwlEn ...

  9. 面试官问我:看过sharding-jdbc的源码吗?我吧啦吧啦说了一通!!

    写在前面 在产品初期快速迭代的过程中,往往为了快速上线而占据市场,在后端开发的过程中往往不会过多的考虑分布式和微服务,往往会将后端服务做成一个单体应用,而数据库也是一样,最初会把所有的业务数据都放到一 ...

  10. jenkins打包java项目缺少jar包问题解决

    java项目在使用jenkins打包时个别jar包可能会没有下载到本地,这时候就要用命令行本地安装一下 打包时基础jar包报错如图: 黑框里依次为: 组ID:-DgroupId=com.azazar ...