链表删除指定节点问题

题目要求:

创建一个长度为n的链表,然后删除链表的倒数第x个结点,
并输出删除操作后的链表。

输入样例:

5 2
1 2 3 4 5
 

输出样例:

1>2->3->5 

方法一

        普通链表删除操作实现:这种方法相对简单一些,主要是找到倒数第x结点的位置,然后执行删除操作,具体实现如下 :

#include <stdio.h>
#include <stdlib.h>

typedef struct node{
	int data;
	struct node *next;
}Node,*Link;

Link create();						//创建头一个带头结点的单链表 
void rear(Link head,int num);		//尾插法把数插入链表 
void delete_(Link head,int save);	// 删除指定节点 
void display(Link head);			//显示链表 

int main()
{
	Link head = create();			//设置头结点 
	int n,x,i,save,num;
	
	scanf("%d %d",&n,&x);
	
	for(i = 0;i < n;i++)
	{
		scanf("%d",&num);
		
		if(i == n - x)				//倒数第x就是正数第n - x(下标) 
		{
			save = num;
		}
		
		rear(head,num);				//将数字依次插入链表中 
	}
	
	delete_(head,save);				//删除倒数第x结点 
	display(head); 					//显示链表 
	return 0;
}

Link create()
{
	Link head = NULL;
	head = (Link)malloc(sizeof(Node));
	
	if(head == NULL)
	{
		printf("error");
		return NULL; 
	}
	
	head->data = 0;					//初始化头节点 
	head->next = NULL;
	
	return head;
}

void rear(Link head,int num)
{
	Link p = head;
	Link pr = NULL;					//pr为新节点,需要动态内存分配 
	pr = (Link)malloc(sizeof(Node));
	
	if(pr == NULL)
	{
		printf("error");
		return ;
	}
	
	pr->data = num;				//将num的值 赋给新节点 

	if(head->next == NULL)		//头节点指向的下一个为空,可以直接插进去 
	{
		head->next = pr;
		pr->next = NULL;		//插进去之后,这个新节点指向的下一个就是空 
	}
	else
	{
		while(p->next != NULL)	//遍历整个链表,注意循环条件是p->next不为空 
		{
			p = p->next; 
		}
		p->next = pr;			//遍历到最后一个退出循环,然后插入新节点 
		pr->next = NULL;
	}
	
	return ;
}

void  delete_(Link head,int save)
{
	Link p,pr;				//设置一前一后两个节点 
	p = head;
	pr = head->next;
	
	if(head == NULL)
	{
		printf("error");
		return ; 
	}
	
	while(pr->data != save && pr->next != NULL)	//不是要删除的数,指向的下一个也不为空,进入循环 
	{
		p = pr;				//每一次前面存后面 
		pr = pr->next;		//继续往下遍历 
	}
	
	if(pr->data == save)	//找到了 
	{
		if(pr == head)		//特殊情况优先考虑 :恰好是头结点,直接删 
		{
			head->next = pr->next;
		}
		else
		{
			p->next = pr->next;
		}
		free(pr);			//记得释放删除的结点 
	}
	return ;
	
}

void display(Link head)
{
	Link pr = head->next;
	while(pr != NULL)
	{
		if(pr->next != NULL)	//注意打印格式,如果下一个不是空,就要打印-> 
		{
			printf("%d->",pr->data);
		}
		else
		{
			printf("%d",pr->data);
		}
		pr = pr->next;			//继续往下遍历 
	} 
	return ;
}

运行结果:

方法二

         通过快慢指针来实现,快慢指着查找删除结点所在的位置,快指针比慢指针多走 x 步,快指针先走了 x 步再让慢指针开始走,两指针一起走,最后返回慢指针,则是删除节点的位置。具体实现如下:

#include <stdio.h>
#include <stdlib.h>
typedef struct node{
	int data;
	struct node *next;
}Node,*Link;

Link create();					//创建头结点 
void rear(Link head,int num);	//尾插法插入新节点 (插入n个num) 
Link find(Link head,int x);		//快慢指针来进行删除操作 
void display(Link head);		//显示链表 

int main()
{
	Link head = create();
	int n,i,x,num;				//输入n 和 倒数第x结点 
	scanf("%d %d",&n,&x);
	
	for(i = 0;i < n;i++)
	{
		scanf("%d",&num);		//录入每个数 
		rear(head,num);			//插入链表 
	}
	
	display(find(head,x));		//陈列 
	return 0;
}

Link create()					//创建头节点 
{
	Link head = NULL;
	head = (Link)malloc(sizeof(Node));
	if(head == NULL)
	{
		printf("分配失败!");
		return NULL;
	}
	
	head->data = 0;
	head->next = NULL;
	return head;
}

void rear(Link head,int num)			//尾插法插入 
{
	Link p = NULL,pr = NULL;
	p = head;
	pr = NULL;
	pr = (Link)malloc(sizeof(Node));
	
	if(pr == NULL)
	{
		printf("分配失败!");
	}
	
	pr->data = num;					//data域赋值 
	if(head->next == NULL)			//只有头结点,直接插入 
	{
		head->next = pr;
		pr->next = NULL;
	}
	else							//否则,遍历到最后 然后插入 
	{
		while(p->next != NULL)
		{
			p = p->next;
		}
		p->next = pr;
		pr->next = NULL;
	}
	
	return ;
	
}

Link find(Link head,int x)			//快慢指针查找操作,找到删除结点的位置 
{
	if(head == NULL || x <= 0)
	{
		return NULL;
	}
	
	Link fast = head,slow = head;	//设一个快慢指针,快指针比慢指针先走n步 
	while(fast != NULL && x > 0)	//快指针先走x步 
	{
		fast = fast->next;
		x--;
	}
	while(fast->next != NULL)		//慢指针开始走 ,注意条件未快指针指向不为空 
	{
		slow = slow->next;
		fast = fast->next;
	}
	if(slow->next != NULL)			//快指针走完,剩下慢指针继续遍历 
	{
		slow->next = slow->next->next;
	} 
	
	return head;
} 

void display(Link head)
{
	Link pr = head->next;
	while(pr != NULL)
	{
		if(pr->next != NULL)			//注意输出格式 
		{
			printf("%d->",pr->data);
		}
		else
		{
			printf("%d",pr->data);
		}
		pr = pr->next;
	}
	return ;
	
}

运行结果:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值