单链表的C语言实现

链表的实现(带头结点)

按照数据结构与算法分析:C语言描述(第二版)(黑皮书)实现。

单链表(指针实现)

类型声明

struct ElementType;
struct Node;
typedef struct Node *Ptr2Node;
typedef Ptr2Node List;
typedef Ptr2Node Position;

struct ElementType
{
    int id;//id是唯一标识
    char name[20];
};

struct  Node{
    ElementType element;
    Position next;
};

初始化

算法流程:创建头节点并分配空间

找特定元素所在位置

算法流程:从首结点开始遍历链表直到找到元素X的位置

找特定元素结点的前驱所在位置

算法流程:从头节点开始遍历链表,直到P->next->element==X

删除

75b00a761aab0ea4e80458bfc478712

算法流程:找待删结点前驱,创建一个中间指针用于删除X指针

void Delete(ElementType X,List &L){
    Position P,tmpCell;

    P=FindPrevious(X,L);
    if(!IsLast(P,L)){
        /*X被找到了*/
        tmpCell=P->next;
        P->next=tmpCell->next;
        tmpCell=NULL;
        free(tmpCell);
    }

}

插入(P位置的下一个位置)

算法流程:新建结点T并分配空间,T->next改为P->next,P->next改为T,(注意顺序)T->element写入X。

//未用到L,插入P位置的下一个位置(即P指向的位置)
void Insert(ElementType X,List &L,Position P){
    Position tmpCell;

    tmpCell=(Position)malloc(sizeof(Node));
    if(tmpCell==NULL){
        printf("out of space\n");
        exit(0);
    }
    tmpCell->element=X;
    tmpCell->next=P->next;
    P->next=tmpCell;
}

完整代码

#include<stdio.h>
#include<stdlib.h>
struct ElementType;
struct Node;
typedef struct Node *Ptr2Node;
typedef Ptr2Node List;
typedef Ptr2Node Position;

int InitList_v1(List &L);
int InitList_v2(List *L);
List MakeEmpty(List L);
int IsEmpty(List L);
int IsLast(Position P,List L);
Position Find(ElementType X,List L);//找X元素结点的位置P
void Delete(ElementType X,List &L);
Position FindPrevious(ElementType X,List L);
void Insert(ElementType X,List &L,Position P);
void DeleteList(List L);
Position Header(List L);//找头节点位置
Position First(List L);//找链表首结点
ElementType Retrieve(Position P);//取P位置的元素值
void PrintList(List L);
void PrintElement(ElementType e);
struct ElementType
{
    int id;//id是唯一标识
    char name[20];
};
struct  Node{
    ElementType element;
    Position next;
};


/*
利用函数引用,L是头节点
*/  
int InitList_v1(List &L){    
    L=(Ptr2Node)malloc(sizeof(Node));//头节点分配空间
    if(L==NULL) return 0;
    L->next=NULL; return 1;
    
}
/*利用指针传地址*/
int InitList_v2(List* L){
    *L=(Ptr2Node)malloc(sizeof(Node));
    if(L==NULL) {
        printf("out of space\n");
        return 0;
    }
    (*L)->next=NULL; return 1;
}

//L为空链表时返回true
int IsEmpty(List L){
    return L->next==NULL;
}
//当前位置是否是链表末尾
int IsLast(Position P,List L){
    return P->next==NULL;
}
//返回某个元素X在表中位置,未找到时返回空指针
Position Find(ElementType X,List L){
    Position P;

    P=L->next;
    while (P!=NULL && P->element.id != X.id)
    {
        P=P->next;
    }
    return P;
}

//返回某个元素X在表中的前驱的位置,未找到时返回到链表的最后位置
Position FindPrevious(ElementType X,List L){
    Position P;

    P=L;//若第一个结点是待查结点,其前驱是头节点(或理解为无前驱)
    while(P->next!=NULL &&P->next->element.id!=X.id)
    {
        P=P->next;
    }
    return P;
}

//删除链表中某个元素X
void Delete(ElementType X,List &L){
    Position P,tmpCell;

    P=FindPrevious(X,L);
    if(!IsLast(P,L)){
        /*X被找到了*/
        tmpCell=P->next;
        P->next=tmpCell->next;
        tmpCell=NULL;
        free(tmpCell);
    }

}
//未用到L,插入P位置的下一个位置(即P指向的位置)
void Insert(ElementType X,List &L,Position P){
    Position tmpCell;

    tmpCell=(Position)malloc(sizeof(Node));
    if(tmpCell==NULL){
        printf("out of space\n");
        exit(0);
    }
    tmpCell->element=X;
    tmpCell->next=P->next;
    P->next=tmpCell;
}

Position Header(List L)
{
    return L;
}

Position First(List L)
{
    return L->next;
}

ElementType Retrieve(Position P)
{
    return P->element;
}

void PrintElement(ElementType e)
{
    printf("id:%d---name:%s\n",e.id,e.name);
}

void PrintList(List L)
{
    printf("LinkList--------------\n");
    printf("location-----next(if exist)------data_id-----data_name\n");
    Ptr2Node P=L->next;//首结点的位置
    while (P!=NULL)
    {
        if(P->next!=NULL){
            printf("0x%x-----0x%x-----%d-----%s\n",P,P->next,
            P->element.id,P->element.name);

        }else{
            printf("0x%x-----%d-----%s\n",P,
            P->element.id,P->element.name);

        }
        
        P=P->next;
    }
    
}

int main(){
    List L;
    InitList_v2(&L);
    printf("%d\n",IsEmpty(L));
    printf("%d\n",IsLast(L,L));
    ElementType e_1={1,"zhangsan"};
    ElementType e_2={2,"lisi"};
    ElementType e_3={3,"Alice"};
    ElementType e_4={4,"Bob"};
    /*
    1插到头节点后
    2插到1后
    3插到头结点后
    */
    Insert(e_1,L,Header(L));
    //Position ptr=Find(e_1,L);
    Insert(e_2,L,Find(e_1,L));
    Insert(e_3,L,Header(L));
    PrintList(L);
    Delete(e_3,L);
    PrintList(L);

    PrintElement(Retrieve( First(L)));
    getchar();
}

静态链表(链表的游标实现)(数组模拟链表)

使用该方法,0号空间和最后一个数组空间被占用,不能存数据

0号空间存放freelist首元素的地址(数组下标)

最后一个数组空间指向链表首元素

freelist是指数组空间中未被利用的部分,这些部分通过cur连成了一个空闲链表

初始化方式应该是:0号空间指向freelist首元素(即1号空间),最后一个空间指向链表首元素(初始化时表内无元素,置为0(视为nullptr))。

重点:倒数第二个空间的cur置为0,因为倒数第二个空间是最后一个可以分配的空间,应该不指向下一个元素了。

类型定义

#define MAXSIZE 5

typedef struct {
	char name[20];
	int score;
}Element; 

typedef struct {
	Element data;
	int cur;  //游标,为0时表示无指向 
}Component,StaticLinkList[MAXSIZE];    
/*
这个写法等价于 
typedef struct {
	Element data;
	int cur;  //游标,为0时表示无指向 
}Component;
typedef Component StaticLinkList[MAXSIZE];    
*********typedef int data[max];   data a;  a就是一个int[max] 
即为Component类型创建一个数组类型,叫 StaticLinkList
*/

/*

完整代码

#include<stdio.h>

//静态链表最大长度 ,能存放数据的位置是maxsize-2,一个位置放空闲结点位置,一个位置当头节点 
#define MAXSIZE 5

typedef struct {
	char name[20];
	int score;
}Element; 

typedef struct {
	Element data;
	int cur;  //游标,为0时表示无指向 
}Component,StaticLinkList[MAXSIZE];    
/*
这个写法等价于 
typedef struct {
	Element data;
	int cur;  //游标,为0时表示无指向 
}Component;
typedef Component StaticLinkList[MAXSIZE];    
*********typedef int data[max];   data a;  a就是一个int[max] 
即为Component类型创建一个数组类型,叫 StaticLinkList
*/

/*
结构体数组 
静态链表第一个元素和最后一个元素特殊处理
第一个元素cur存备用链表第一个结点的下标
最后一个元素cur存第一个有数值的元素的下标(头结点) 
*/

//初始化静态链表
int InitLinkList(StaticLinkList space){
	for(int i=0;i<MAXSIZE-2;i++){
		space[i].cur=i+1;
	}
	space[MAXSIZE-2].cur=0; 
	space[MAXSIZE-1].cur=0;//当前链表为空
	return 1; 
} 


void PrintElement(Element e){
	printf("element--%d--%s	\n",e.score,e.name);
}

void PrintSpace(StaticLinkList space){
	printf("=====================\n"); 
	for(int i=0;i<MAXSIZE;i++){
		if(space[i].data.score==NULL){
			printf("Pos--%d	Next--%d\n",i,space[i].cur);
		}
		else{
			printf("Pos--%d	Next--%d	",i,space[i].cur);
			PrintElement(space[i].data);	
		}
	}
} 

/*
第一个元素的cur指向备用链表第一个结点下标
最后一个有值元素的cur设为0(指向第一个结点,然后第一个结点会指向备用链表的头) 
*/
//分配空闲链表,即返回空闲链表的第一个下标 ,若空闲链表空返回0 
int Malloc_SSL(StaticLinkList space){
	int i=space[0].cur; //指向备用链表的第一个结点的下标
	
	if(space[0].cur){
		if(space[i].cur!=MAXSIZE-1)//若i的游标不指向最后一个位置 
		{  
			space[0].cur=space[i].cur;  //更新第一个结点的cur 
		} 
		else{
			printf("这是可分配的最后一个结点\n");
			space[0].cur=0; // 设置第一个结点的cur为0,表示无空闲数组 
		} 
	}
	if(i==0)
		printf("无空闲结点\n");
	return i; //i是空闲链表的1第一个下标 
}

//表长
int Length_SSL(StaticLinkList space){
	int cnt=0;
	int node_i=space[MAXSIZE-1].cur;
	//最后一个有值元素的cur为0,cnt前n-1个元素 
	while(node_i!=0){
		cnt++;
		node_i=space[node_i].cur;
	}

	return cnt;
}
 

//插入  插到第i个位置,即原链表第i个元素的前面 
int Insert_SSL(StaticLinkList space,int i,Element e){
	
	//1 -> length+1 length+1个插入位置 
	if(i<1||i>Length_SSL(space)+1){
		printf("insert position unreasonable\n");
		return 0;
	} 
	
	int free_location=Malloc_SSL(space);//分配结点位置 
	//判断是否有空闲 
	if(free_location==0){
		printf("freelist is full\n");
		return 0;
	}
	space[free_location].data=e;
	
	//找原来的第i-1个元素,即k 
	int k=MAXSIZE-1;
	for(int j=0;j<i-1;j++){
		k=space[k].cur;
	} 
	
	space[free_location].cur=space[k].cur;
	space[k].cur=free_location;
	return 1; 
} 

//回收下标为k的结点(撤销分配的元素)
int Free_SSL(StaticLinkList space,int k){
	//k不能是第一个和最后一个结点 
	if(k<1||k>=MAXSIZE-1){
		printf("回收位置不合理");
		return 0;
	}
	space[k].data.score=NULL;
	space[k].cur=space[0].cur;//k的cur指向原来的优先空位 
	space[0].cur=k;  //使k位置成为优先空位 
	return 1;
}
 
//删除第i个元素          
int Delete_SSL(StaticLinkList space,int i){
	if(i<1||i>Length_SSL(space)){
		printf("删除位置不合理");
		return 0; 
	} 
	int k=MAXSIZE-1; //最后一个结点
	int j;
	//找第i-1个元素
	for(j=1;j<=i-1;j++){
		k=space[k].cur;
	}
	
	//如果第i-1个元素是第0个元素?若删除掉了最后一个元素,游标得置为0 

	j=space[k].cur;//j位置是第i个元素
	space[k].cur=space[j].cur;//第i-1个元素的游标改为第i+1个元素的位置 
	Free_SSL(space,j);//释放第i个元素所在位置 
	return 1; 
}


int main(){
	StaticLinkList space;
	InitLinkList(space);
	Element e_1={"zhang1",1};
	Element e_2={"zhang1",2};
	Element e_3={"zhang1",3};
	Element e_4={"zhang1",4};
	Element e_5={"zhang1",5};
	
	Insert_SSL(space,1,e_1);
	Insert_SSL(space,2,e_2);
	PrintSpace(space);
	
	Insert_SSL(space,3,e_3);
	Insert_SSL(space,4,e_4);
	PrintSpace(space);
	
	Insert_SSL(space,1,e_5);
	PrintSpace(space);
	
	printf("\n cnt=%d",Length_SSL(space));
	Delete_SSL(space,0);
	Delete_SSL(space,4);
	Delete_SSL(space,2);
	PrintSpace(space);
	
	printf("\n cnt=%d",Length_SSL(space));
	//Insert_SSL(space,3,e_2);
	Insert_SSL(space,2,e_2);
	PrintSpace(space);
	
	printf("\n cnt=%d",Length_SSL(space));
	Delete_SSL(space,1);
	Delete_SSL(space,1);
	PrintSpace(space);
	
	Delete_SSL(space,1);
	PrintSpace(space);
	
	
//	printf("\n cnt=%d",Length_SSL(space));
//	Insert_SSL(space,1,e_1);
//	
//	printf("\n cnt=%d",Length_SSL(space));
//	Insert_SSL(space,2,e_2);
//	PrintSpace(space);
//	
//	
//	printf("\n cnt=%d",Length_SSL(space));
//	Insert_SSL(space,3,e_3);
//	printf("\n cnt=%d",Length_SSL(space));
//	Insert_SSL(space,1,e_5);//出错 
//	PrintSpace(space);
//	printf("\n cnt=%d",Length_SSL(space));

	printf("\n cnt=%d",Length_SSL(space));
	Insert_SSL(space,3,e_1);
	
	printf("\n cnt=%d",Length_SSL(space));
	Insert_SSL(space,2,e_2);
	PrintSpace(space);
	
	
	printf("\n cnt=%d",Length_SSL(space));
	Insert_SSL(space,2,e_3);
	printf("\n cnt=%d",Length_SSL(space));
	Insert_SSL(space,1,e_5);//出错 
	PrintSpace(space);
	printf("\n cnt=%d",Length_SSL(space));
	return 0;
}
  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值