栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

史上最全单链表的增删改查反转等操作汇总以及5种排序算法(C语言)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

史上最全单链表的增删改查反转等操作汇总以及5种排序算法(C语言)

[TOC]

1.准备工作

首先包含头文件,定义链表结构体,产生随即链表的范围,定义全局头尾节点。

#include 
#include 
#include 
#define MAX 10

typedef struct Node 
{
    int data;
    struct Node *next;  
}Node;

Node *head = NULL;
Node *end = NULL;
2.创建链表

int CreatList(int a)
{
    
    Node *temp = (Node *)malloc(sizeof(Node));
    if (temp ==NULL)
    {
 printf("malloc error!");
 return -1;
    }
    else
	{
		
		temp->data = a;
		temp->next = NULL;
		
		if (head == NULL)
		{
			head = temp; 
			end = temp;    
		}
		else
		{
			end->next = temp;
			end = temp;
		}
    }  
}
3.打印链表

void PrintList(Node *temp)
{
    if(temp == NULL)
    {
 printf("Empty List!rn");
    }
    while (temp)
    {
printf("%d",temp->data);
temp = temp->next;
	   if(temp)
	   printf("->");
    }
    printf("rn");
}
4.在元素后面插入元素

向链表中增添元素,根据添加位置不同,可分为以下 3 种情况:
1.插入到链表的头部(头节点之后),作为首元节点;
2.插入到链表中间的某个位置;
3.插入到链表的最末端,作为链表中最后一个数据元素;

虽然新元素的插入位置不固定,但是链表插入元素的思想是固定的,只需做以下两步操作,即可将新元素插入到指定的位置:
a.将新结点的 next 指针指向插入位置后的结点;
b.将插入位置前结点的 next 指针指向插入结点;

例如,我们在链表 {1,2,3,4} 的基础上分别实现在头部、中间部位、尾部插入新元素 5,其实现过程如图 所示:


int InsertListEnd(int index,int a)
{
    if (head == NULL)
    {
 printf("Empty List!rn");
 return 0;
    }
	if (FindList(index)->next == FindList(a))
		return 0;
	else
	{
	  
		Node *temp = FindList(index);
		
		Node *pt = (Node *)malloc(sizeof(Node));
		pt->data = a;
		
		if (temp == end)
		{
			//尾巴的下一个指向新插入的节点
			end->next = temp;
			//新的尾巴
			end = temp;
		}
		else
		{
			// 先连后面 (先将要插入的节点指针指向原来找到节点的下一个)
			pt->next = temp->next;
			//后连前面
			temp->next = pt;
			printf("The list after insert %d is rn",a);
			PrintList(head);
		}
	}

}
5.在元素前面增加元素

int InsertListHead(int index,int a)
{
    if (head == NULL)
    {
 printf("Empty List!rn");
 return 0;
    }
	
	if (FindList(index)->next == FindList(a))
		return 0;
	else
	{
	   
		Node *temp = FindList(index);
		
		Node *pt = (Node *)malloc(sizeof(Node));
		pt->data = a;
		
		if (temp == head)
		{
			//尾巴的下一个指向新插入的节点
			pt->next = head;
			//新的头
			head = pt;
		}
		else
		{
			
			Node *pre = FindPreNode(temp);
			pre->next = pt;
			pt->next = temp;
			printf("The list after insert %d is rn",a);
			PrintList(head);
		}
	}

}
6.删除链表元素,要注意删除链表尾还是链表头

从链表中删除指定数据元素时,实则就是将存有该数据元素的节点从链表中摘除,但作为一名合格的程序员,要对存储空间负责,对不再利用的存储空间要及时释放。因此,从链表中删除数据元素需要进行以下 2 步操作:

1.将结点从链表中摘下来;
2.手动释放掉结点,回收被结点占用的存储空间;

其中,从链表上摘除某节点的实现非常简单,只需找到该节点的直接前驱节点 temp,执行一行程序:

temp->next=temp->next->next;

例如,从存有 {1,2,3,4} 的链表中删除元素 3,则此代码的执行效果如图 2 所示:


void DeleteListHead()
{ //记住旧头
	Node *temp = head;
	//链表检测
	if (NULL == head)
	{
		printf("Empty list!n");
		return;
	}

	head = head->next; //头的第二个节点变成新的头
	free(temp);
}

void DeleteListTail()
{
	if (NULL == end)
	{
		printf("链表为空,无需删除n");
		return;
	}
	//链表不为空
	//链表有一个节点
	if (head == end)
	{
		free(head);
		head = NULL;
		end = NULL;
	}
	else
	{
		//找到尾巴前一个节点
		Node *temp = head;
		while (temp->next != end)
		{
			temp = temp->next;
		}
		//找到了,删尾巴
		//释放尾巴
		free(end);
		//尾巴迁移
		end = temp;
		//尾巴指针为NULL
		end->next = NULL;
	}
}

void DeleteList(int a)
{
   //链表判断 是不是没有东西
	if (NULL == head)
	{
		printf("Empty list!n");
		return;
	}
	//链表有东西,找这个节点
	 Node *temp = FindList(a);
	if (NULL == temp)
	{
		printf("%d not findrn",a);
		return;
	}
	//找到了,且只有一个节点
	if (head == end)
	{
		free(head);
		head = NULL;
		end = NULL;
 printf("The list after delete %d is empty!rn",a);

	}
	else if (head->next == end) //有两个节点
	{
		//看是删除头还是删除尾
		if (end == temp)
		{
			DeleteListTail();
     printf("The list after delete %d is rn",a);
     PrintList(head);
		}
		else if (temp == head)
		{
			DeleteListHead();
     printf("The list after delete %d is rn",a);
     PrintList(head);
		}
	}
	else //多个节点
	{
		//看是删除头还是删除尾
		if (end == temp)
			DeleteListTail();
		else if (temp == head)
			DeleteListHead();
		else //删除中间某个节点
		{	//找要删除temp前一个,遍历
			Node *pt = head;
			while (pt->next != temp)
			{
				pt = pt->next;
			}
			//找到了
			//让前一个直接连接后一个 跳过指定的即可
			pt->next = temp->next;
			free(temp);
     printf("The list after delete %d is rn",a);
     PrintList(head);
		}
	}
    
}
7.根据传入的数值查询链表

Node *FindList(int a)
{
    Node *temp = head;
    if(head == NULL)
    {
 printf("Empty List!rn");
 return NULL;
    }
  
    else
    {
while (temp)
{
    if (temp->data == a)
    {
  printf("%d find!rn",a);
  return temp;
    }
    temp = temp->next;
}
     printf("%d not find!rn",a);
     return 0;
    }
    
}
8.修改链表元素

void ModifyList(Node *phead,int element,int modify)
{
	Node *temp = phead;
	while((temp!= NULL))
	{
		
		if(temp->data == element)
		{
			temp->data	= modify;
			
		}	
		temp = temp->next;
	}
}
9.求链表长度

int LengthList(Node *temp)
{
    int length = 0;
    while (temp)
    {
 length++;
 temp = temp->next;
    }
    return length;
    
}
10.前驱,后继节点的查找
Node *FindPreNode(Node *p)
{
	Node *temp = head;
	
	if(p == head)
	{
		printf("%d is head nodern",p->data);
		return NULL;
	}
	else
	{
		while((temp->next != p) && (temp !=NULL))
		{
			
			temp = temp->next;

		}
		return temp;		
	}

}
Node *FindNextNode(Node *p)
{
	Node *temp = head;
	
	while(temp &&(temp != p))
	{
		temp = temp->next;

	}
	
	temp = temp->next;
	return temp;
	 
}

11.倒置链表

Node *InvertList(Node *phead)
{
 if(phead == NULL || phead->next == NULL)
		{
  return phead;
 }
		else
		{
  Node *p = phead;
  Node *q = NULL;
  Node *r = NULL;
  while(p != NULL)
				{
						
   q = p->next;
						
   p->next = r;
						
   r = p;
						
   p = q;
  }
				head = r;
  return head;
 }
}

 Node *ReverseList(Node *phead)
    {
		
		
 Node *ptmp = NULL;
 Node *tmp = NULL;
		
 if(NULL == phead)
		{
  printf("link is emptyn");
  return NULL;
 }else
		{
				
  while(phead != NULL)
				{
   tmp = phead;
   phead = phead->next;
						
   tmp->next = ptmp;
						
   ptmp = tmp;
  }
 }
		head = ptmp;
 return ptmp;
}
12.判断链表是否有环

int Is_Circular(Node *phead)
{
 if(phead == NULL || phead->next == NULL){
  return 0;
 }
		
 Node *p1 = phead;
 Node *p2 = phead;
 while(p1 != NULL && p2 != NULL){
  p2 = p2->next; 
  if(p1 == p2)
   return 1;
  p2 = p2->next;
  p1 = p1->next;
 }
 return 0;
}

测试函数

int main ()
{
    int i = 0;  
    
	srand((int)time(0)); 
    for (i =5;i>0;i--)
	CreatList(rand()%MAX);
	// CreatList(i);
	printf("新创建的的链表为:");
	PrintList(head);
	InsertListHead(4,10);
	printf("在4前插入10后的链表为:");
	PrintList(head);
	InsertListEnd(4,10);
	printf("在4后插入10后的链表为:");
	PrintList(head);
	DeleteList(0);
	printf("删除0后的链表为:");
	PrintList(head);
	Node *p = FindList(7);
	Node *q = FindList(4);
	ModifyList(head,1,15);
	printf("修改1为15后的链表为:");
	PrintList(head);
	ReverseList(head);
	printf("反转后的链表为:");
	PrintList(head);
	printf("链表长度为:%d",LengthList(head));
    return 0;
}

测试截图

关于排序算法的讲解将在下节[单链表的5种排序算法]介绍。

以上代码均为测试后的代码。如有错误和不妥的地方,欢迎指出。

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号