单链表的表示与实现(C语言)

1、结点结构

在这里插入图片描述

2、存储结构

typedef struct LNode
 {     
       ElemType data;//数据域  
       struct LNode *next; //指针域
 }ListNode,*LinkList; //ListNode是链表的结点类型,LinkList是指向链表结点的指针类型
LinkList L; //L被定义为指向单链表的指针类型
ListNode *L;//与上等价

3、单链表上的基本运算

(1)初始化单链表

void InitList(LinkList *L) /* 初始化单链表*/ 
{    
  if((*L=(LinkList)malloc(sizeof(ListNode)))==NULL) /* 为头结点分配一个存储空间*/  
 	exit(-1);   
  (*L)->next=NULL;  /* 将单链表的头结点指针域置为空*/ 
 } 
void InitList(LinkList &L) /* 初始化单链表*/ 
{    
  if((L=(LinkList)malloc(sizeof(ListNode)))==NULL) /* 为头结点分配一个存储空间*/  
  exit(-1);   
  L->next=NULL;  /* 将单链表的头结点指针域置为空*/ 
 } 

(2)单链表判空

int ListEmpty(LinkList L)   
/*判断单链表是否为空*/
{
    if(L->next==NULL)   /*如果链表为空*/
        return 1;    /*返回1*/
    else      /*否则*/
        return 0;     /*返回0*/
}

(3)查找第i个结点

查找单链表中第i个结点。查找成功返回该结点的指针,否则返回NUL

ListNode *Get(LinkList L,int i)   
/*查找单链表中第i个结点。查找成功返回该结点的指针,否则返回NUL*/
{
	ListNode *p;
	int j=0;
	p=L;
	if(ListEmpty(h))  /*查找第i个元素之前,判断链表是否为空*/
   		 return NULL;
   	if(i<1)    /*判断该序号是否合法*/
        	return NULL;
   	while(p->next!=NULL&&j<i)
	{
    		p=p->next;
    		j++;
	}
	if(j==i)    /*如果找到第i个结点*/
    		return p;  /*返回指针p*/
	else;    /*否则*/
    		return NULL ;/*返回NULL*/
}

这是王道书中的代码算法

ListNote *Get(Listlist L,int i)
{
	int j=1;//计数,从1开始
	LNote *p=L->next;
	if(i==0)
		return L;
	if(i<1)
		return NULL;
	while(p&&j<i)
	{
		p=p->next;
		j++;
	}
	return p;
}

(4)查找线性表中元素值为e的元素

查找线性表中元素值为e的元素,查找成功返回对应元素的结点指针,否则返回NULL

ListNode *LocateElem(LinkList L,ElemType e)   
/*查找线性表中元素值为e的元素,查找成功返回对应元素的结点指针,否则返回NULL */
{
	ListNode *p;
	p=L->next;  /*指针p指向第一个结点*/
	//前两句等价于ListNode *p=L->next;  
	while(p!=NULL&&p->data!=e)
		p=p->next;  /*则继续查找*/
	return p;    /*返回结点的指针*/
}

查找线性表中元素值为e的元素,查找成功返回对应元素的序号,否则返回0

int LocatePos(LinkList L,ElemType e)   
/*查找线性表中元素值为e的元素,查找成功返回对应元素的序号,否则返回0*/
{
	ListNode *p;
	int i=1;
	if(ListEmpty(L))  /*查找第i个元素之前,判断链表是否为空*/
    		return 0;
	p=L->next;  /*从第一个结点开始查找*/
	while(p)//如果p不为空
	{
    		if(p->data==e) /*找到与e相等的元素*/
        		return i;  /*返回该序号*/
    		else   /*否则*/
    		{
        		p=p->next; /*继续查找*/
        		i++;
    		}
	}
	if(!p)    /*如果没有找到与e相等的元素,返回0,表示失败*/
    		return 0;
}

(5)第i个位置插入值e的结点

在单链表中第i个位置插入值e的结点。插入成功返回1,失败返回0

int InsertList(LinkList L,int i,ElemType e)
/*在单链表中第i个位置插入值e的结点。插入成功返回1,失败返回0*/
{
	ListNode *p,*pre; 
	int j=0;
	//==============这一部分可以调用GET函数=======
	pre=L;   /*指针p指向头结点*/
	while(pre->next!=NULL&&j<i-1)/*找到第i-1个结点,即第i个结点的前驱结点*/
	{
    		pre=pre->next;
    		j++;
	}
	if(j!=i-1)     /*如果没找到,说明插入位置错误*/
	{
   		 printf("插入位置错");
    		return 0;
	}
	//===========替换为pre=Get(L,i-1)=========
	
	/*新生成一个结点,并将e赋值给该结点的数据域*/
	if((p=(ListNode*)malloc(sizeof(ListNode)))==NULL)
    		exit(-1);
	p->data=e;
	/*插入结点操作*/
	p->next=pre->next;
	pre->next=p;
	return 1;
}

(6)删除单链表中的第i个位置的结点

方法一:先检查删除位置的合法性,然后查找第i-1个结点,将前驱结点直接指向后驱结点,再将其删除,时间复杂度为O(n)

int DeleteList(LinkList L,int i,DataType &e)
/*删除单链表中的第i个位置的结点。删除成功返回1,失败返回0*/
{
	ListNode *pre,*p;
	int j=0;
    	pre=L;
       	//==================这一部分可以调用GET函数=======
    while(pre->next!=NULL&&pre->next->next!=NULL&&j<i-1)
    /*在寻找的过程中确保被删除结点存在*/
    {
        pre=pre->next;
        j++;
    }
    if(j!=i-1)    /*如果没找到要删除的结点位置,说明删除位置错误*/
    {
        printf("删除位置错误");
        return 0;
}
//================================
    p=pre->next; 
    e=p->data;
/*将前驱结点的指针域指向要删除结点的下一个结点,也就是将p指向的结点与单链表断开*/
    pre->next=p->next;
    free(p);    /*释放p指向的结点*/
    return 1;
}

方法二:将后继结点q值赋给要删除的结点p,然后删除后继结点

q=p->next;//令q为p后继结点
p->data=p->next->data;//将p替换成后继结点q
p->next=q->next;
free(q);//释放掉后继

(7)求线性表的表长

求表长是不包括头结点的其他结点个数,下面算法是带有头结点的单链表。

int ListLength(LinkList L)
/*求线性表的表长*/
{
    ListNode *p;
    int count=0;
    p=L;
    while(p->next!=NULL)
    {
        p=p->next;
        count++;
    }
    return count;
}

(8)销毁链表

void DestroyList(LinkList L)
/*销毁链表*/
{
    ListNode *p,*q;
    p=L;//p指向头结点
    while(p!=NULL) //第一次循环时
   {
        q=p;//q指向头结点
        p=p->next;//p指向第一个结点
        free(q);//释放掉头结点,循此往复
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值