链表之单链表

逻辑结构:线性:首元素没有直接前驱,尾元素没有直接后继,其余元素有且只有一个前驱和后继
存储结构:链式存储
插入:头插可以替换尾插 头节点的作用是让插入的代码统一,不用去判断。

链表的结构:

 

链表的结构如上图所示,每个节点的内部结构为两个部分,data为节点内保存的数据,next为保存下一个节点的地址。

typedef int linklist_data_t;
typedef struct linklist
{
	linklist_data_t data;
	struct linklist* next;
}lkl_node,*lkl_pnode;

链表的创建:

lkl_pnode create_linklist()
{
	lkl_pnode H=(lkl_pnode)malloc(sizeof(lkl_node));//开辟堆区空间
	if(H==NULL)
	{
		printf("malloc is default\n");
		return NULL;
	}
	H->next=NULL;//防止出现野指针
	return H;//创建头节点
}

链表的创建需要在堆区开辟一片空间,这样可以手动开辟手动销毁。

 链表的插入:

 1、尾插:顾名思义就是从链表的尾部插入一个新节点。第一步,让头节点往后移到要插入新节点位置的前一个位置;第二步,将data存入p中;第三步,将 H 的next指向p,p的next指向空指针(NULL)。

while(H->next)
	{
		H=H->next;
	}
	lkl_pnode p=create_linklist();
	p->data=data;
	H->next=p;
	p->next=NULL;

2、头插:顾名思义就是从节点之前插入新节点。第一步,让头节点往后移到要插入新节点位置的前一个位置;第二步,将data存入p中;第三步,将p的next指向p的下一个节点即H的next;

第四步,将H的next指向p。

while(H->next)
	{
		H=H->next;
	}
	lkl_pnode p=create_linklist();
	p->data=data;
	p->next=H->next;
	H->next=p;

链表的增加:

当H的next为NULL时头插和尾插一样,所以头插可以替换尾插。

int increase_linklist(lkl_pnode H,int pos,linklist_data_t data)
{
	if(pos<0||pos>getlen_linklist(H))//判断插入位置是否合理,pos表示新节点插入的位置
	{
		printf("pos is default\n");
	}
	while(pos--)//遍历链表找到要插入新节点位置的前一个位置
	{
		H=H->next;
	}
	lkl_pnode new=create_linklist();
	new->data=data;
	new->next=H->next;
	H->next=new;
	return 0;
}

获取链表长度:

定义一个整型变量用来计数,然后遍历整个链表,可以得到链表的长度。

int getlen_linklist(lkl_pnode H)
{
	int count=0;
	while(H->next)
	{
		H=H->next;
		count++;
	}
	return count;
}

链表的判断是否为空:

当链表长度为0时链表为空。返回值为0表示正常退出,返回值为-1表示异常退出。

int empty_linklist(lkl_pnode H)
{
	if(0==getlen_linklist(H))
	{
		return 0;
	}
	else
	{
		return -1;
	}
}

链表的打印: 

int show_linklist(lkl_pnode H)
{
	if(0==empty_linklist(H))
	{
		printf("H is empty\n");
		return -1;
	}
	int i=0;
	while(H->next)
	{
		H=H->next;
		printf("data[%d]=%d ",i,H->data);
		i++;
	}
	puts("\n");
	return 0;
}

链表的删除(根据位置删除):

遍历链表找到要删除节点的前一个位置,然后将要删除节点的位置保存下来,存到p中,然后将要删除节点的前一个位置与要删除节点的后一个位置相连,最后释放要删除节点的空间。

int delete_linklist(lkl_pnode H,int pos)
{
	if(0==empty_linklist(H))
	{
		printf("H is empty\n");
		return -1;
	}
	if(pos<0||pos>=getlen_linklist(H))
	{
		printf("pos is default\n");
	}
	while(pos--)
	{
		H=H->next;
	}
	lkl_pnode p=H->next;
	H->next=p->next;
	free(p);
	p=NULL;
	return 0;
}

 链表的删除(根据值删除):

这里方法与根据位置删除的方法一样,只不过在找要删除节点的前一个位置时不一样,因为是根据值删除,所以在遍历时条件是当头节点的下一个节点的值不等于data时,如果是头节点的值不等于data,找到的是要删除的节点它自己。

int delete1_linklist(lkl_pnode H,linklist_data_t data)
{
	if(0==empty_linklist(H))
	{
		printf("H is empty\n");
		return -1;
	}
	while(H->next->data!=data)
	{
		H=H->next;
	}
	lkl_pnode p=H->next;
	H->next=p->next;
	free(p);
	p=NULL;
	return 0;
}

链表的修改(根据位置修改):

方法也是找到即将修改的节点的前一个节点,然后将它的下一个节点的值变为data。

int change_linklist(lkl_pnode H,int pos,linklist_data_t data)
{	
	if(0==empty_linklist(H))
	{
		printf("H is empty\n");
		return -1;
	}
	if(pos<0||pos>=getlen_linklist(H))
	{
		printf("pos is default\n");
	}
	while(pos--)
	{
		H=H->next;
	}
	H->next->data=data;
	return 0;
}

链表的修改(根据值修改):

首先找到即将的修改节点,遍历链表,条件应当为H的值不等于旧的data,这样就找到了即将修改的节点,然后将它的值改为新的data。

int change1_linklist(lkl_pnode H,linklist_data_t old_data,linklist_data_t new_data)
{
	if(0==empty_linklist(H))
	{
		printf("H is empty\n");
		return -1;
	}
	while(H->data!=old_data)
	{
		H=H->next;
	}
	H->data=new_data;
	return 0;
}

链表的查询(根据位置查询):

因为查询后返回值为一个数据,所以函数的数据类型应当为linklist_data_t型;首先还是找到需要查询节点的前一个节点,最后返回它下一个节点的data。

linklist_data_t search_linklist(lkl_pnode H,int pos)
{
	if(0==empty_linklist(H))
	{
		printf("H is empty\n");
		return -1;
	}
	if(pos<0||pos>=getlen_linklist(H))
	{
		printf("pos is default\n");
	}
	while(pos--)
	{
		H=H->next;
	}
	return H->next->data;
}

 链表的查询(根据值查询):

函数返回值为查询到值节点的位置;首先遍历整个链表判断H的值是否与data相等,如果等返回节点的位置,不等则继续遍历。

int search1_linklist(lkl_pnode H,linklist_data_t data)
{
	if(0==empty_linklist(H))
	{
		printf("H is empty\n");
		return -1;
	}
	int i=0;
	while(H->next)
	{
		H=H->next;
		if(H->data==data)
		{
			return i;
		}
		i++;
	}
	return 0;
}

 链表的逆序:

首先定义p和q来保存头节点的下一个节点位置,然后断开头节点连接,然后让p移动,q则保存p的位置,然后q做头插,这样就成了每个节点做头插,形成逆序。

int reverse_linklist(lkl_pnode H)
{
	if(0==empty_linklist(H))
	{
		printf("H is empty\n");
		return -1;
	}
	lkl_pnode p=H->next;
	lkl_pnode q=H->next;
	H->next=NULL;
	while(p)
	{
		q=p;
		p=p->next;
		q->next=H->next;
		H->next=q;
	}
	return 0;
}

链表的排序: 

这里和链表的逆序方法雷同,只不过在p遍历的同时遍历头节点的下一个节点,判断头节点下一个节点的值是否大于q的值,如果大于退出循环,然后做头插,如果小于继续遍历p。

int sort_linklist(lkl_pnode H)
{
	if(0==empty_linklist(H))
	{
		printf("H is empty\n");
		return -1;
	}
	lkl_pnode p=H->next;
	lkl_pnode q=H->next;
	H->next=NULL;
	while(p)
	{
		q=p;
		p=p->next;
		lkl_pnode t=H;
		while(t->next)
		{
			if(t->next->data>q->data)
			{
				break;
			}
			t=t->next;
		}
		q->next=H->next;
		H->next=q;
	}
	return 0;
}

 链表的清空:

只需遍历链表是否为空,一个一个删除,就清空了。

int clean_linklist(lkl_pnode H)
{
	if(0==empty_linklist(H))
	{
		printf("H is empty\n");
		return -1;
	}
	while(empty_linklist(H))
	{
		delete_linklist(H,0);
	}
	return 0;
}

链表的销毁:

判断链表是否为空,为空就释放头节点,让头节点等于NULL,防止出现野指针,不为空就先清空,然后释放头节点。

int destroy_linklist(lkl_pnode *H)
{
	if(0==empty_linklist(*H))//如果为空就释放头节点
	{
		free(*H);
		*H=NULL;
	}
	else//不为空就清空后再释放头节点
	{
		clean_linklist(*H);
		free(*H);
		*H=NULL;
	}
	return 0;
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值