关于单链表的操作



前言

链表的基本操作思路都不难,但是函数很多,在学习的过程中也不能只敲函数,还要多联系完整版的链表,要有输出,今天就教大家写完整版的代码啦。还有我在学习链表的时候遇到的困难,也帮大家避雷啦。


一、关于链表的创建

#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
   int data;
   struct Node*next;
}Node,*Linklist;
//Node 表示一个Node类型的指针,*Linklist则代表传入的一整个链表;

//初始化单链表(建立链表必须要做的事)
Linklist Insertlist()
{
	Linklist head;
	head = (Node*)malloc(sizeof(Node));
	head->next = NULL;
	return head;
}

//接下来用尾插法建立一个单链表,
//也可以用头插,但是头插法建立的单链表是倒序的
void creatlist(Linklist head)
{
	Node* r, * s;
	r = head;
	int data;
	while (1) {
		scanf_s("%d", &data);
		if (data == 0)
		{
			break;
		}
		s = (Node*)malloc(sizeof(Node));
		s->data = data;
		r->next = s;
		r = s;
		r->next = NULL;
	}
}

二、单链表的应用

1.删除排序链表中的重复元素

思路:由于给定的链表的排好序的,所以重复的元素在链表中的位置是连续的,因此我们只需要对链表进行一次遍历,找到相同的元素让他指向下一个就行。

代码如下(示例):

//删除两个相同的元素
Linklist deletesome(Linklist head)
{
	if (head == NULL || head->next == NULL)
		return head;
	Node* p = head;
	while (p) {
		if (p->data == p->next->data) {
			p->next = p->next->next;
		}
		else {
			p = p->next;
		}
	}
	return head;
}

2.找到中间结点

代码如下(示例):

//找到中间节点
void middlenode(Linklist head)
{
	Node* fast = head->next;
	Node* slow = head->next;
	while (fast != NULL && fast->next != NULL) {
		fast = fast->next->next;
		slow = slow->next;
	}
   printd("%d ",slow->data);
}

3.反转链表

思路:对于反转链表,其实有很多方法,比如直接用头插法创建链表再打印出来就可以反转,也可以改变指针的指向(后面写回文联表会用到,一般用于不带头结点的链表),这里我们介绍一种比较好理解的递归(用于带有节点的链表)。

代码如下(示例):

void daoxv(Linklist head)
{
	if (head->next != NULL) {
		daoxv(head->next);
	}
	printf("%d ", head->data);
}

4.合并两个有序链表

题目:将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
在这里插入图片描述

思路:通过遍历链表比较连个链表的大小,重新定义指针的排序,可以直接比较,也可以用递归简化代码;

代码如下(示例):

//递归
 Linklist mergeTwoLists(Linklist list1,Linklist list2)
{
 if (list1 == NULL) {
  return list2;
 }
 if (list2 == NULL) {
  return list1;
 }
 if (list1->data >= list2->data) {
  list2->next = mergeTwoLists(list1, list2->next);
  return list2;
 }
 else {
  list1->next =mergeTwoLists(list1->next, list2);
  return list1;
 }
}

主函数(包含以上所有函数)

int main()
{
	Linklist head;
	Linklist list1,list2,list3;
	Linklist head;
	head = Insertlist();
	list1 = Insertlist();
	list2 = Insertlist();
	list3 = Insertlist();
	creatlist(list1);
	creatlist(list2);
	creatlist(list3);
	creatlist(head);
	middlenode(head);
	deletesome(head);
	daoxv(head->next);
	mergeTwoLists(list1,list2,list3);
	print(head);
	
}

5.回文链表(不带头节点)

题目:给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。

思路:回文链表可以用数组,递归和快慢指针的方式,在这里我们采用快慢指针来做,加深对不带头节点的链表反转的理解。

整个流程可以分为以下五个步骤:
找到前半部分链表的尾节点。
反转后半部分链表。
判断是否回文。
恢复链表。
返回结果。

代码如下(示例):

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

typedef struct Node {
 int data;
 struct Node* next;
}Node, * Linklist;
void Insertlist(Linklist* L)
{
 *L = NULL;
}


Linklist creatlist(Linklist* L)
{
 Node* s, * r;
 int data;
 scanf_s("%d", &data);
 if (data != -1)
 {
  *L = (Linklist)malloc(sizeof(Node));
  (*L)->next = NULL;
  (*L)->data = data;
  r = *L;
  scanf_s("%d", &data);
  while (data != -1)
  {
   s = (Node*)malloc(sizeof(Node));
   s->data = data;
   s->next = NULL;
   r->next = s;
   r = r->next;
   scanf_s("%d", &data);
  }
 }
 return *L;
}

bool  huiwen(Linklist L)
{
 if (L == NULL || L->next == NULL)
  return true;
 if (L->next->next == NULL) {
  if (L->data == L->next->data)
   return true;
  else
   return false;
 }
 Node* fast, * slow;
 fast = L->next->next;
 slow = L->next;

 while (fast && fast->next != NULL) {
  fast = fast->next->next;
  slow = slow->next;
 }
 Node* p, * q;
 p = q = NULL;
 while (L != slow) {
  q = L->next;
  L->next = p;
  p = L;
  L = q;
 }
 if (fast != NULL && fast->next == NULL)
  {
  slow = slow->next;
 }

 while (p != NULL)
 {
  if (p->data != slow->data)
   return false;
  p = p->next;
  slow = slow->next;
 }
 return true;
}

int main()
{
 Linklist L;
 Insertlist(&L);
 creatlist(&L);
 if (huiwen(L)) {
  printf("true\n");
 }
 else {
  printf("false\n");
 }
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值