前言
在学习单链表的过程中,发现了很多问题:
1.结构体的有关问题
2.链表的表示问题
在这篇文章中,刚开始将会说明这两个问题,然后再讨论单链表的有关操作。
1.结构体
不论是顺序表还是链表,都用到了结构体。接下来通过本篇中的程序来说明结构体
typedef struct Node
{
ElemType data;//数据域
struct Node* next;//存放后继节点的指针域
}Node;
typedef struct Node* LinkList;//定义了新类型:结构指针Linklist来代表struct Node*
在这个结构体定义中,第一句的”typedef struct Node”语句中的”Node“”是不可以省略的,而在顺序表的定义中却是可以省略的,之所以不能省略,是因为链表的结构体中”truct Node* next;”语句用到了自身的类型;而且语句“struct Node”为一个结构类型,和int,char 都是类型说明符
在这块代码中,语句“typedef struct Node* LinkList;”,struct Node是一个指针类型,与int 或者char* 是差不多的,这句话用typedef把他用Linklist替换了,为了下面写代码节省时间
2.链表的表示
链表中所说的节点其实就是结构体,所谓链表,就是许多个结构体连接在一起,这就组成了链表。
在链表操作的函数中,有使用了LinkList* L,这一形参,这其实是定义了一个指向指针的指针,在操作的时候(*L)就相当于解引用,为(*L)->next;。而如果形参定义为LinkList L,就直接用L->next;
3.内容布局
此篇文章中用到了动态内存申请+模块化设计的方法,最重要的一个模块是创建一个新结点。不管在初始化整表,添加,删除等操作都用到了这个模块,这篇文章涉及到的操作有:
1.插入链表
1.1.头插法
1.2.尾插法
1.3.在任意位置插入
2.删除链表
2.1整表删除
2.1在任意位置删除
3.显示输出链表
4.获取元素
对代码的一些解释带附在代码中
4.操作的一些图解
代码如下
//单链表:结构体变量与结构体通过指针连接到一起
/*动态内存申请+模块化设计
1.创建链表,创建一个表头表示整个链表,链表就是一个结构体变量
2.创建节点,形成新的节点
3.插入节点,删除节点
5.遍历*/
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
typedef int Status;
typedef int ElemType;
typedef struct Node
{
ElemType data;//数据域
struct Node* next;//存放后继节点的指针域
}Node;
typedef struct Node* LinkList;//定义了新类型:结构指针Linklist来代表struct Node*
LinkList creatNode(int data);//创建新结点(插入,得先有新的,才让你插
LinkList creatList();//创建链表(头结点)
Status listHeadInsert(LinkList List);//头插入
Status listTailInsert(LinkList List);//尾插入
Status listDisplay(LinkList head);//遍历显示链表
Status listInsert(LinkList *L,int i,ElemType e);//插入
Status listDelete(LinkList *L,int i,ElemType *e);//删除
Status clearList(LinkList* L);//清空链表
Status getElem(LinkList L,int i,ElemType *e);//查找元素
int main()
{
LinkList List = creatList();//创建一个链表(头结点)
Status i;
ElemType e;
int n=0,j=0,x=0;
while(n!=7)
{
printf(" \n");
printf("**************************************************\n");
printf("*1.尾插*2.头插*3.插入*4.删除*5.清空*6.查找*\n");
scanf("%d",&n);
switch(n)
{
case 1:
listTailInsert(List);
printf("添加数据后的链表:\n");
listDisplay(List);
break;
case 2:
listHeadInsert(List);
printf("添加数据后的链表:\n");
listDisplay(List);
break;
case 3:
printf("请选择在第几个元素前插入:\n");
scanf("%d",&j);
printf("请输入插入的数据:\n");
scanf("%d",&x);
i = listInsert(&List,j,x);
if(i==ERROR)
printf("插入失败\n");
else
printf("插入成功\n");
printf("操作后的顺序表:\n");
listDisplay(List);
break;
case 4:
printf("请选择删除第几个元素:\n");
scanf("%d",&j);
i = listDelete(&List,j,&e);
if(i==ERROR)
printf("删除失败\n");
else
printf("删除成功\n");
printf("操作后的顺序表:\n");
listDisplay(List);
break;
case 5:
i = clearList(&List);
if(i==ERROR)
printf("格式化失败\n");
else
printf("格式化成功\n");
break;
case 6:
printf("请选择查找第几个元素:\n");
scanf("%d",&x);
i = getElem(List,x,&e);
if(i==ERROR)
printf("查找失败\n");
else
printf("查找成功,第%d个元素的值为:%d\n",x,e);
break;
}
}
}
LinkList creatNode(int data)//创建新结点(插入,得先有新的,才让你插
{
LinkList newNode = (LinkList)malloc(sizeof(Node));//生成新结点
newNode->data = data;
newNode->next = NULL;
return newNode;
}
LinkList creatList()//创建链表(头结点)
{
LinkList headNode = (LinkList)malloc(sizeof(Node));//headNode为一个结构体变量
headNode->next;
return headNode;
}
/* 1.声明一结构指针newNode,和计数器变量i,数据x
2.newNode指向一生成的新结点
3.给newNode->data赋值,再模块中完成
4.将newNode插入到头结点与前一新结点之间 */
Status listHeadInsert(LinkList List)//插入节点(头插入)
{
LinkList newNode;//声明一指针p,作用为生成新结点
int i,x=0;
printf("请输入要添加的数(头插):\n");
for(i=0;x!=-1;i++)
{
scanf("%d",&x);
if(x!=-1)
{
newNode = creatNode(x);//生成新结点
newNode->next = List->next;
List->next = newNode;//插入到表头
}
}
return OK;
}
Status listTailInsert(LinkList List)//插入节点(尾插入)
{
LinkList newNode,tailNode=List;//声明一指针newNode,作用为生成新结点,tailNode指向尾部的节点
int i,x=0;
printf("请输入要添加的数(尾插):\n");
for(i=0;x!=-1;i++)
{
scanf("%d",&x);
if(x!=-1)
{
newNode = creatNode(x);//生成新结点
tailNode->next = newNode;
tailNode = newNode;//插入到表头
}
}
tailNode->next = NULL;
return OK;
}
Status listDisplay(LinkList head)//head其实是头结点
{
LinkList pMove;//声明一指针p
pMove = head->next;//让p指向链表L的第一个节点
while(pMove)//打印的位置不能为空
{
printf("%d ",pMove->data);
pMove = pMove->next;//让pMove指向下一个节点
}
printf("\n");
return OK;
}
Status listInsert(LinkList *L,int i,ElemType e)
{
int j = 1;//j为计数器
LinkList newNode,sNode;
newNode = *L;
while(newNode&&j<i)
{
newNode = newNode->next;
++j;
}
if(!newNode||j>i)
return ERROR;//第i个结点不存在
sNode = creatNode(e);
sNode->next = newNode->next;
newNode->next = sNode;
return OK;
}
Status listDelete(LinkList *L,int i,ElemType *e)
{
int j = 1;//j为计数器
LinkList nNode,sNode;
nNode = *L;
while(nNode->next&&j<i)
{
nNode = nNode->next;
++j;
}
if(!nNode||j>i)
return ERROR;//第i个结点不存在
sNode = nNode->next;
nNode->next = sNode->next;
*e = nNode->data;
free(sNode);
return OK;
}
Status clearList(LinkList* L)//清空列表
{
LinkList p,q;
p = (*L)->next;
while(p)//没到表尾
{
q = p->next;
free(p);
p = q;
}
(*L)->next = NULL;
return OK;
}
Status getElem(LinkList L,int i,ElemType *e)
{
int j = 1;
LinkList p;
p = L->next;
while(p&&j<i)
{
p = p->next;
++j;
}
if(!p||j>i)
return ERROR;
*e = p->data;
return OK;
}
运行结果
后记
上述代码把链表的各种操作柔和到一个方程里面,以致于代码有些庞大,但是在实际操作中还可以适当加减操作
以上就是单链表的表示和各种操作,喜欢的多多支持哦~