C 单链表的理解与基本操作---从数组与链表区别出发!

之前在复习的时候,复习到链表。就总结了这篇,如果你看到这篇博客,希望可以帮到你!

大家在学习C语言的时候最常用的就是数组了,但是其实链表的作用也是非常大的。首先来给大家share一下数组和链表的结构有哪些不同!

一:结构上的不同

 首先链表是链式的存储结构,而数组则是顺序的存储结构。数组是把所有的元素依次的存储,而链表则是通过结构体指针来链接元素与元素。对于基本操作来说,链表的插入与删除就较为简单,不用移动每一个元素,但是寻找起来就很费劲,寻找一个元素,需要访问其前边所有的元素。而数组的话,是支持随机访问的,寻找起来也是很方便的,但是插入和删除就比较麻烦,首先数组是设定固定长度的,当达到最大长度时候,扩充数组的长度就没有链表方便。

二:相同点

两种结构均可实现顺序存储。

三:什么时候用数组?什么时候用链表?

如果你需要的一块动态的存储空间,且数据的多少不确定,变化比较大就可以使用链表。但是如果你不需要频繁插入删除操作,切对空间长度没有要求的时候就推荐是用数组。

四:链表的组成

链表是由一系列的节点组成。每个节点包含两个部分:数据域和指针域。数据域是用来存储数据元素的,指针域则是存储下一个节点地址的。且在物理的存储结构上是非连续、非顺序的存储结构,每个元素的逻辑顺序也是通过结构体中的指针链接次序实现的。

五:关于链表的基本操作

  • 链表数据结构的定义

    • 此结构体中定义了一个integer型的数据,即为每个节点数据域存放的数据类型。定义了一个结构体类型的指针,通过此指针来链接各节点。

     

typedef  struct LinkList{
	int  date;
	struct LinkList *next;
}Node,linkList;

 

  • 链表的创建:
    • 初始化含有n个的节点的链表,思想:通过循环先将当前节点初始化,之后不断用当前节点指向末尾节点,并将末尾节点的指针域设为空。

     

linkList * creat_LinkList(int n){
	linkList *PHead ,*PCurrent, *PEnd;  //创立头节点PHead、当前节点PCurrent、末尾节点PEnd
	PHead = (linkList *)malloc( sizeof(linkList));
	if( PHead == NULL){  
		return NULL;
	}
	PEnd = PHead;		//开始阶段,未插入节点前只有头节点,所以末尾节点和头节点是一个。
	//此时开始创建节点,
	for (int i = 1; i <= n; i++)
	{
		//初始化当前节点
		PCurrent = (linkList *)malloc( sizeof(linkList));
		printf("please  input  value  of  the NO%d date !",i);
		scanf("%d",PCurrent->date);
		PCurrent -> next = NULL;
		//当前节点指向末尾节点。
		PEnd -> next = PCurrent;
		PEnd = PCurrent;
	}
	//将末尾节点的指针域设为空。
	PEnd->next = NULL;
	return PHead;
}
  •  修改链表节点的值
    • 思想:传入链表和要修改的链表节点,用变量flag来标记节点,用暂时替代链表replace取代传入链表,与flag同事进行遍历,如果当flag和传入链表节点相同则找到要修改的节点,进行修改。
void alter_LinkListNode(linkList *List ,int alter_position){
	int flag = 0;
	linkList * replace = List;
	//运用while循环来判定是否找到要修改节点的位置,找到则跳出循环。replace则是要修改的节点。
	while (flag < alter_position && replace != NULL )
	{
		replace = replace ->next ;
		flag++;
	}
	if( replace != NULL){
		printf("please  input  date  of  you want !");
		scanf("%d",&replace -> date);
	}else
	{
		printf("you  want  alter  the   date doesn't exist!");
	}

}
  • 删除链表节点: 
    • 此时跟大家说一下,删除的操作如图所示:

 如图所示:   删除链表节点其实就是将要【 删除节点的上一个节点 】的指针域所指向的下一节点的地址改成 【 删除节点的下一个节点 】的地址,此操作之后,将要删除的节点的内存空间释放掉。

思想:首先要了解free的概念。C语言中并没有像JAVA一样的废弃内存空间回收机制,所以对于不用的内存空间需要手动释放,这时便用到了free。在删除链表节点的时候,很多人都会直接写成pre_Node -> next = pre_Node -> next -> next,然后free(pre_Node -> next)。然而此时你释放掉pre_Node ->next之后,后面的链表节点就找不到了,因为上一步你是直接把pre_Node -> next直接释放掉了,这样整个链表就断掉,后面当然就找不到了。free(pre_Node)  是指删除pre_Node指向节点所占的内存,不是删除pre_Node本身所占内存。所以我们要定义一个临时的节点pre_Node,来代替要删除节点的上一节点。

void  delete_LinkListNode( linkList *List , int deleteNode_date){
		linkList * delete_Node ,* pre_Node = List; 
		while ( pre_Node != NULL )
		{
					if( pre_Node -> next -> date == deleteNode_date  && pre_Node != NULL ){
						delete_Node = pre_Node ->next;   //此时delete_Node和pre_Node -> next指向的都是pre_Node->next存储空间的地址。
														 //这时free(delete_Node)之后,还有pre_Node -> next保留以保证链表不会断掉。
						pre_Node ->next = delete_Node ->next;
						free(delete_Node);
						printf("删除成功!");

				}else
				{
					pre_Node = pre_Node -> next;
				}
		}
}
  • 插入链表节点
    • 如图所示:和删除的操作基本相同,在插入之前节点p的指针域p->next指向的是节点H,在插入节点之后,插入的节点就相当于H的位置,所以此时只需要把H节点与插入的节点连接起来,同时将插入的节点与P链接起来就可以了。即为:q -> next = p -> next ;  p -> next = q ;    此时两个步骤顺序是不可以更改的,如果你先将p -> next = q ;  然后将q -> next = p ->next ;  此时是把插入节点和插入节点的下一节点连接了起来,而上一节点和插入节点就断掉了,切记!!!!!

通过形参传入链表以及要插入链表节点的位置,以及插入节点数据域的数据。如果遍历链表找到标记与节点相同,则证明找到,否则继续遍历。

void insert_LinkLstNode(linkList *List , int insert_position ,int insert_date){
		int  flag = 0;  //flag用于标记节点,判断时候找到插入位置
		linkList * q ,* p = List;
		if ( insert_position < 0 || p == NULL)
		{
			  printf("插入失败");
		}
		else
		{
			while (p != NULL)
			{
				if (insert_position == flag )
				{
					q = (linkList *)malloc(sizeof(linkList));
					q -> date = insert_date;
					q -> next = p -> next;
					p -> next = q;
					break;
				}
				else
				{
					flag++;
					p = p -> next;
				}
			}
		}
}
  • 打印列表
    •   打印链表就比较简单了,只需要遍历即可。

	//打印链表。思想:打印列表便比较简单,直接传入一个头指针,之后遍历整个链表进行输入。
	void  print_LinkList(linkList * H){
	
		linkList * P = H ->next;
		printf("the value of date is : %5d\n",P->date);
		while (P != NULL)
		{
			P = P->next;
		}

	}

如果您看完有任何不理解的地方,或者有任何补充,欢迎在下方留言!

猜你喜欢

转载自blog.csdn.net/qq_36657788/article/details/82584521