数据结构之链表的基本操作,该篇的链表是以存放字符为依据的(%c),如果想要表中保存整型类的数据,可以将前面转定义的Elemtype改为int
该链表头的数据域我们是打算放链表的长度的,但是这里会有一个问题就是我的数据域定义了字符型,之后的链表长度是要有++,--等等运算操作的,所以在后面的长度运用,我们可以使用强制类型转化将字符型转化为整型(后面出现的“a=(int)L->data”就是为了实现上面的操作)
定义好链表
typedef struct LNode//打算在链表头放链表长度
{
ElemType data;
struct LNode*next;
}LinkNode;
初始化链表
status InintList(LinkNode *L)//初始化链表和顺序输入链表内容
{
int mark;
LinkNode*p, *xin;
L = (LinkNode*)malloc(sizeof(LinkNode));
if (!L)
{
printf("申请失败!即将退出");
return 0;
}
L->next = NULL;
p = L;
printf("表头已经申请完成");
printf("是否继续申请空间:(1:是/0:不是)");
scanf("%d", &mark);
while (mark)
{
Interrupt();
xin = (LinkNode*)malloc(sizeof(LinkNode));
if (!xin)
{
printf("申请失败!即将退出");
return;
}
printf("请输入该节点的数据:");
scanf("%c", &xin->data);
Interrupt();
p->next = xin;
xin->next = NULL;
p = xin;
printf("是否继续申请空间:(1:是/0:不是)");
scanf("%d", &mark);
}
len(L);
return (L);
}
输出链表内容
status DispList(LinkNode *L)//输出链表的内容
{
LinkNode*p;
int a;
a=(int)L->data;
if (a== 0)
{
printf("空表\n");
return 0;
}
else
{
p = L->next;
printf("该表内容为:");
while (p)
{
printf("%-5c", p->data);
p = p->next;
}
}
return ok;
}
获取链表元素位置
status GetElem(LinkNode *L, int i, ElemType e)//获取链表第i个的元素
{
LinkNode*p;
int j,a;
printf("请输入要提取的数值位置:");
scanf("%d", &i);
Interrupt();
a = (int)L->data;
if (i<1 || i>a)
{
printf("该链表没有该位置的数值,即将返回");
return;
}
p = L->next;
for (j = 0; j < i - 1; j++)
{
p = p->next;
}
e = p->data;
printf("已经找到该位置的数值,该数值为%c", e);
}
插入链表
status ListInsert(LinkNode *L, int i)//插入链表
{
LinkNode *p,*xin;
int a,j,di=0;
a = (int)L->data;
mark:Interrupt();
printf("请输入要插入的位置:");
scanf("%d", &i);
if (i<1 || i>a+ 1)
{
printf("输入错误,请重新输入!");
goto mark;
}
xin = (LinkNode*)malloc(sizeof(LinkNode));
if (!xin)
{
printf("申请失败!即将退出");
return;
}
Interrupt();
printf("请输入该节点的数据:");
scanf("%c", &xin->data);
for (p = L,j=1;j<=a; j++)
{
if (j == i)
{
xin -> next = p -> next;
p->next = xin;
di = 1;
break;
}
p = p->next;
}
if (di == 0)
{
p->next = xin;
xin->next = NULL;
}
a++;
L->data=(char)a;
return ok;
}
删除链表的某个元素
status ListDelete(LinkNode *L, int i)//在链表中删除第i个元素
{
LinkNode *p, *q;
int j,a;
a = (int)L->data;
mark:Interrupt();
printf("请输入要删除的元素位置:");
scanf("%d", &i);
if (i<1 || i>a)
{
printf("输入错误,请重新输入!");
goto mark;
}
for (p = L, q = p->next,j=1; j <= a;j++)
{
if (j == i)
{
p->next = q->next;
free(q);
break;
}
p = p->next;
q = q->next;
}
a--;
L->data = (char)a;
return ok;
}
------------------------------------------------以上为顺序表的基本操作-----------------------------------------------
代码中用到多次的中断函数(解决scanf的bug--->猜测)
void Interrupt()//中断函数
{
while (1) //用于检测换行符,使函数脱离scanf的连续输出
if (getchar() == '\n')
break;
}
下方的完整代码还有求长度、释放、输出元素位置等等操作
代码会和书上的有所不同,因为我把一些操作都集成到原本的函数里面了,可以看一下大概的思路
使用的编译器是:vs2013
下方是完整的代码(供参考,如果有错误的话还请指正,谢谢):
#define _CRT_SECURE_NO_WARNINGS//链表
#include <stdio.h>
#include <malloc.h>
//全局定义特殊变量
#define ok 1
#define OVERFLOW 0
//转定义区域
typedef char ElemType;
typedef int status;
typedef struct LNode//打算在链表头放链表长度
{
ElemType data;
struct LNode*next;
}LinkNode;
//函数声明区域
void Interrupt();//创建一个中断函数
void len();//求单链表长,将长度数值放在链表头的data(要强制转化数据类型)
void Interrupt()//中断函数
{
while (1) //用于检测换行符,使函数脱离scanf的连续输出
if (getchar() == '\n')
break;
}
status InintList(LinkNode *L)//初始化链表和顺序输入链表内容
{
int mark;
LinkNode*p, *xin;
L = (LinkNode*)malloc(sizeof(LinkNode));
if (!L)
{
printf("申请失败!即将退出");
return 0;
}
L->next = NULL;
p = L;
printf("表头已经申请完成");
printf("是否继续申请空间:(1:是/0:不是)");
scanf("%d", &mark);
while (mark)
{
Interrupt();
xin = (LinkNode*)malloc(sizeof(LinkNode));
if (!xin)
{
printf("申请失败!即将退出");
return;
}
printf("请输入该节点的数据:");
scanf("%c", &xin->data);
Interrupt();
p->next = xin;
xin->next = NULL;
p = xin;
printf("是否继续申请空间:(1:是/0:不是)");
scanf("%d", &mark);
}
len(L);
return (L);
}
status DispList(LinkNode *L)//输出链表的内容
{
LinkNode*p;
int a;
a=(int)L->data;
if (a== 0)
{
printf("空表\n");
return 0;
}
else
{
p = L->next;
printf("该表内容为:");
while (p)
{
printf("%-5c", p->data);
p = p->next;
}
}
return ok;
}
void len(LinkNode *L)//求单链表长,将长度数值放在链表头的data
{
LinkNode*p; int i = 0;
p = L->next;
while (p)
{
p = p->next;
i++;
}
L->data = i;
}
status listLength(LinkNode *L)//链表长度
{
int a;
a = (int)L->data;
if (a== 0)
{
printf("该链表长度为0");
}
else
{
printf("该链表长度为%d", a);
}
return ok;
}
status ListEmpty(LinkNode *L)//判断链表是否为空
{
int a;
a = (int)L->data;
if (a== 0)
{
printf("该链表为空");//实际上返回值是T
}
else
{
printf("该链表不为空");//实际上返回值是F
}
return ok;
}
status GetElem(LinkNode *L, int i, ElemType e)//获取链表第i个的元素
{
LinkNode*p;
int j,a;
printf("请输入要提取的数值位置:");
scanf("%d", &i);
Interrupt();
a = (int)L->data;
if (i<1 || i>a)
{
printf("该链表没有该位置的数值,即将返回");
return;
}
p = L->next;
for (j = 0; j < i - 1; j++)
{
p = p->next;
}
e = p->data;
printf("已经找到该位置的数值,该数值为%c", e);
}
status LocateElem(LinkNode *L, ElemType e)//查找元素e在链表的位置
{
LinkNode*p;
int i=0;
Interrupt();
printf("请输入要查找位置的元素:");
scanf("%c", &e);
p = L->next;
while (p)
{
if (p->data == e)
{
printf("该元素在链表第%d个位置", i + 1);
return ok;
}
i++;
p = p->next;
}
printf("该元素不在链表中");
return ok;
}
status ListInsert(LinkNode *L, int i)//插入链表
{
LinkNode *p,*xin;
int a,j,di=0;
a = (int)L->data;
mark:Interrupt();
printf("请输入要插入的位置:");
scanf("%d", &i);
if (i<1 || i>a+ 1)
{
printf("输入错误,请重新输入!");
goto mark;
}
xin = (LinkNode*)malloc(sizeof(LinkNode));
if (!xin)
{
printf("申请失败!即将退出");
return;
}
Interrupt();
printf("请输入该节点的数据:");
scanf("%c", &xin->data);
for (p = L,j=1;j<=a; j++)
{
if (j == i)
{
xin -> next = p -> next;
p->next = xin;
di = 1;
break;
}
p = p->next;
}
if (di == 0)
{
p->next = xin;
xin->next = NULL;
}
a++;
L->data=(char)a;
return ok;
}
status ListDelete(LinkNode *L, int i)//在链表中删除第i个元素
{
LinkNode *p, *q;
int j,a;
a = (int)L->data;
mark:Interrupt();
printf("请输入要删除的元素位置:");
scanf("%d", &i);
if (i<1 || i>a)
{
printf("输入错误,请重新输入!");
goto mark;
}
for (p = L, q = p->next,j=1; j <= a;j++)
{
if (j == i)
{
p->next = q->next;
free(q);
break;
}
p = p->next;
q = q->next;
}
a--;
L->data = (char)a;
return ok;
}
status DestroyList(LinkNode *L)//释放顺序表
{
L->next = NULL;
len(L);
printf("已经成功释放链表!");
return (L);
}
int main()
{
int a, f = 0, i = 0;
ElemType e = 0;
LinkNode *L = NULL;//定义好链表头
while (1)
{
printf("\n");
printf("================================\n");
printf("| 链表操作系统 |\n");
printf("================================\n");
printf("| 1.初始化链表 |\n");
printf("| 2.输出链表内容 |\n");
printf("| 3.输出链表长度 |\n");
printf("| 4.判断链表情况 |\n");
printf("| 5.输出指定位置元素 |\n");
printf("| 6.输出指定元素位置 |\n");
printf("| 7.插入链表指定位置 |\n");
printf("| 8.删除链表指定位置 |\n");
printf("| 9.释放链表 |\n");
printf("| 0.退出链表操作系统 |\n");
printf("================================\n");
printf("请选择功能(0-9):");
mark:scanf("%d", &a);
switch (a)
{
case 0:f = 1; break;
case 1:L=InintList(L); break;
case 2: DispList(L); break;
case 3:listLength(L); break;
case 4: ListEmpty(L); break;
case 5: GetElem(L, i, e); break;
case 6: LocateElem(L, e); break;
case 7: ListInsert(L, i); break;
case 8:ListDelete(L, i); break;
case 9: L=DestroyList(L); break;
default:printf("选择功能错误!请重新选择菜单功能:"); goto mark;
}
if (f == 1)
{
printf("已经退出系统");
break;//该break是为了退出while的无限“菜单”循环
}
}
}
在主函数所运用到的传参大部分没有实际作用(单纯是为了尽量保持书本的参数一致),因为集成一些操作的原因,很多都在当前想要实现功能的函数里面进行了输入数据和相关的调整