在本篇文章中我们使用不带头结点链表来实现线性表的一系列操作。
1.初始化
不带头结点链表的初始化,只需要将链表头指针head赋值为NULL即可。该操作同样可以简单地在主函数中,直接对head赋初值实现。
/*初始化
*函数功能:初始化线性表
*传入形参:线性表指针 PtrL
*返回值:无
*/
void MakeEmpty(List* PtrL)
{
*PtrL = NULL; //将表指针赋值为NULL,形成一个空表
}
2.求表长
/*求表长
*函数功能:求线性表的表长
*传入形参:线性表指针 PtrL
*返回值:线性表长度 j
*/
int Length(List PtrL)
{
List p = PtrL; //p指向表中的第一个结点
int j = 0;
while(p){
p = p->Next;
j++;
}
return j;
}
3.根据序号查找
/*查找(按序号)
*函数功能:按照序号查找
*传入形参:准备查找的序号 K,线性表指针 PtrL
*返回值:找到了,返回指向该结点的指针 p,未找到,返回NULL
*/
List FinKth(int K,List PtrL)
{
List p = PtrL;
int i = 1; //刚开始时,p指向的是第一个结点
for(p = PtrL; NULL != p && i != K; p = p->Next) //中止条件:找到第K个结点或者遍历完毕
i++;
return p;
}
因为要使得“当未找到时,返回NULL”,所以遍历结束的标志便写为NULL != p,而不是NULL != p->Next。
4.根据值查找
在该函数上我稍做了些修改:更改前,原函数的根据值查找,返回的只是该值第一次出现的位置。
更改后,能够将该数出现的全部位置返回,并存储在一个位置数组中。并将出现的次数存储在计数变量count中。
更改思路:由于c语言返回值只能有一个,所以直接由上一级函数提供存储空间(List Pst[],count),通过地址传递实现多值返回。
因此,计数变量(count)以及位置数组(Pst)都得在主函数中定义,count用于保存X出现的次数,Pst用于保存X出现的位置的地址值。
也同样基于以上原因,函数需要的形参较多。 -。-!
/*查找(按值)
*函数功能:按照数值查找
*传入形参:准备查找的数 X,线性表指针 PtrL,位置数组Pst,计数变量地址 count
*返回值:无
*/
void Find(ElementType X,List PtrL,List Pst[],int* count)
{
List p;
int i = 0;
for(p = PtrL; NULL != p; p = p->Next){//为了将最后一个数也比较上,所以截至条件为“NULL != p”
if(p->Data == X){
Pst[i] = p;
i++;
}
}
*count = i;
}
5.插入
简单的图示如下:
代码如下:
/*插入
*函数功能:在位序i前(在位序i-1后)插入一个新元素X
*传入参数:准备插入的数 X,插入位置 i,线性表指针 L
*返回值: 线性表指针 PtrL
*/
List insert(ElementType X,int i,List PtrL)
{
List s,tmp;
if(i == 1){ //如果插入位置是在第1个之前,即让新节点成为第一个结点
s = (List)malloc(sizeof(LNode));
s->Next = PtrL; //令s->next指向原链表中第一个元素
PtrL = s; //使PtrL指向s,s成为第一个元素
s->Data = X;
}else{
tmp = FinKth(i-1,PtrL);//在第i个元素之前插入,需要更改第i-1元素的next,所以需要找到第i-1个元素的指针
s = (List)malloc(sizeof(LNode));
s->Next = tmp->Next; //使s->next同样指向第i个元素(连接好后面)
tmp->Next = s; //使第i-1个元素指向s(连接好前面)
s->Data = X;
}
return PtrL;
}
插入第一个位置的情况与其他情况分开的原因:在处理非首节点的插入时,对两个链域操作我们需要的是前一个结点的地址。而不带头结点链表第一个结点是没有前一个结点的,所以要将两种情况(插入第一个位置&其他)分开处理。
6.删除
图示如下:
代码如下:
/*插入
*函数功能:删除在位序i(在位序i-1后)的结点
*传入参数:插入位置 i,线性表指针 L
*返回值:新线性表指针 L
*/
List Delete(int i,List PtrL)
{
List s,tmp;
if(i == 1){//如果删除位置是在第1个,即让第二个结点成为第一个结点
s = PtrL;// 将要删除的结点地址暂存
PtrL = PtrL->Next;//建立新的链关系
free(s);//释放空间
}else{
tmp = FinKth(i-1,PtrL);//要删除第i个元素,需要更改第i-1元素的next,所以需要找到第i-1个元素的指针
s = tmp->Next;//删除结点地址暂存
tmp->Next = s->Next;//建立新的链关系
free(s);//释放空间
}
return PtrL;
}
测试主程序如下:
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
typedef int ElementType;
typedef struct LNode* List;
typedef struct LNode{
ElementType Data;
List Next;
}LNode;
void MakeEmpty(List* PtrL); //初始化一个空线性表
List FinKth(int K,List PtrL);//根据位序K,返回相应元素
void Find(ElementType X,List PtrL,List Pst[],int* count);//在线性表中查找X出现的位置
List insert(ElementType X,int i,List PtrL);//在位序i前插入一个新元素X
List Delete(int i,List PtrL);//删除指定位序的元素
int Length(List PtrL); //返回线性表L的长度
int main()
{
List head = NULL;
List p;
List tmp;
int K;//查找用序号
int X;//查找用数字
List Pst[Length(head)];//位置数组
int i;
int count;//计数变量
//初始化
MakeEmpty(&head);
//输入
printf("input:");
do{
tmp = (List)malloc(sizeof(LNode));
scanf("%d",&tmp->Data);
if(head == NULL){
head = tmp;
}else{
for(p = head;p->Next;p = p->Next);
p->Next = tmp;
}
tmp->Next = NULL;
p = tmp->Next;
if(getchar() == '\n')
break;
}while(1);
//求表长
printf("The length is %d\n",Length(head));
//按序号查找
printf("Please input sequence number:");
scanf("%d",&K);
FinKth(K,head) == NULL?printf(" K over range\n"):printf("The number at %dth is:%d\n",K,FinKth(K,head)->Data);
//按值查找
printf("Please input the number what you want to find:");
scanf("%d",&X);
Find(X,head,Pst,&count);
if(count == 0){
printf("The number you are looking for does not exist");
}else{
printf("The position is:");
for(i = 0; i < count; i++)
printf("%d ",Pst[i]);
}
printf("\n");
//插入
printf("Please input the number to insert:");
scanf("%d",&X);
printf("Please input the position:");
scanf("%d",&K);
head = insert(X,K,head);
printf("output:");
for(p = head; p != NULL; p = p->Next){
printf("%d ",p->Data);
}
printf("\n");
//删除
printf("Please input the position to delete:");
scanf("%d",&K);
head = Delete(K,head);
//输出
printf("output:");
for(p = head; p != NULL; p = p->Next){
printf("%d ",p->Data);
}
//释放空间
free(head);
}
测试结果如下:
测试环境:win10 使用软件:DEV_C++
参考文献:何钦铭,《数据结构讲义》,浙江大学