从零开始的链表

新人小白,初学代码。本博客简单的说一下自己学链表的心得,如有错误,欢迎指出。

链表的定义

链表是一种常见的基础数据结构,可以动态的进行存储分配,也就是说,链表是一个功能极为强大的数组,他可以在节点中定义多种数据类型,还可以根据需要随意增添,删除,插入节点。链表都有一个头指针,一般以head来表示,存放的是一个地址。链表中的节点分为两类,头结点和一般节点,头结点是没有数据域的。链表中每个节点都分为两部分,一个数据域,一个是指针域。链表就如同车链子一样,head指向第一个元素:第一个元素又指向第二个元素;……,直到最后一个元素,该元素不再指向其它元素,它称为“表尾”,它的地址部分放一个“NULL”(表示“空地址”),链表到此结束。 作为有强大功能的链表,对他的操作当然有许多,比如:链表的创建,修改,删除,插入,输出,排序,反序,清空链表的元素,求链表的长度等等。

在这里插入图片描述

链表的头文件和创建链表

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define TYPE int

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

typedef struct List
{
	Node* head;
	Node* tail;
	size_t size;

}List;

创建结点

Node* creat_node(TYPE data)
{
	Node* node = malloc(sizeof(Node));//获取内存
	node->data = data;
	node->next = NULL;//初始化
	return node;
}

创建链表

List* creat_list(void)
{
	List* list = malloc(sizeof(List));
	list->head = NULL;  
	list->tail = NULL;  //初始化
}

下面讲讲链表的几个功能

从头部添加

void head_add_list(List* list,TYPE data)
{
	Node* node = creat_node(data);
	if(0 == list->size)
	{
	list->head = node;
	list->tail = node;//当链表的size为零时,头部添加就是将head和tail变成node	
	}
	else
	{
		node->next = list->head;//将node的next指针指向原头部
		list->head = node;//将链表的头部指针指向node
	}
	list->size++;//头部添加完成后将size++
}

从尾部添加

void tail_add_list(List* list,TYPE data)//尾部添加就是和头部反一下
{
	Node* node = creat_node(data);
	if(0 == list->size)
	{
	list->head = node;
	list->tail = node;
	}//当size为零时,链表就没有头尾之分了,所以和头添加一样,将node放进去就好了
	else
	{
	list->tail->next = node;
	list->tail = node;
	}将原尾部的next指向node,在将list的tail指向node就可以将node变成尾部。
	list->size++;//添加数后将size++
}

从头部删除

bool head_del_list(List* list)
{
	if(0 == list->size)return false;//当size为0时就没有可以删除的啦,所以返回false
	Node* node = list->head;
	if(1 == list->head);//当size为1时,头删除就是将唯一的数删掉
	{
	list->head = NULL;
	list->tail = NULL;//将头部和尾部全部指向空指针
	}
	else
	{
		list->head = node->next;//将链表头部指向要删除的node的下一个数
	}
		free(node);//释放node
		list->size--;//删除一个数就要将size--
		return true;
}

销毁

void destory_list(List* list)
{
while(0<list->size)
	{
	head_dal_list(list);
	}
	free(list);
}

从尾部删除

bool tail_dal_list(List* list)
{
if(0 == list->size)return false;//当size为0就没什么好删除的啦,返回false
Node* node = list-tail;
if(1 == list->size)
	{
	list->tail = NULL;
	list->tail = NULL;//当size为1时,就把唯一的数删除,将tail和head全指向NULL就好了
	}
	Node* prev = list->head;
	while(prev->next != list->tail)
	{
	prev = prev->next;
	}//通过while循环找到尾部的前一个值
	free(list->tail);//释放尾结点
	list->tail = prev;
	prev->next = NULL;
	list->size--;//删除一个数后size--
	return true;
}

插入一个数

bool insert_list(List* list,int index,TYPE data)
{
if(index < 0 || index >= list->size)return false;//当插入的位置不存在时返回false
if(0 == index)
	{
	head_add_list(list,data);
	}
else
	{
	Node* prev = list->head;
	for(int i=0;i<index-1;i++)
	{
		prev = prev->next;
	}//通过for循环找到要插入位置的上一个结点
	Node* node = creat_node(data);
	node->next = prev->next;
	prev->next = node;
	}
	list->size++;//插入一个数也要size++
	return true;
}

删除指定位置的数

bool del_index_list(List* list,int index)
{
if(index < 0 || index >list->size)return false;//当删除的数的位置不存在时,返回false
if(0 == index)return head_del_list(list);
if(list->size-1 == index)return tail_del_list(list);//当要删的是头和尾时可以直接调用前面的头删除和尾删除

	Node* prev = list->head;
	for(int i=0;i<index-1;i++)
	{
	prev = prev->next;	
	}//用for循环找到要删除位置的前一个结点
	Node* node = prev->next;
	prev->next = node->next;
	free(node);
	list->size--;
	return true;
}

删除指定值

bool del_value_list(List* list,TYPE data)
{
if(data == list->head->data)
	{
	head_del_list(list);
	return true;
	}//当头部的数据和要删的一样就可以直接调用前面的头部删除函数
	Node* prev = list->head;
	while(NULL != prev->next)
	{
	if(data == prev->next->data)//通过while循环找到要删除的值的前一个结点
		{
		Node* node = prev->next;
		prev->next = node->next;
		free(node);
		list->size--;//删除后要size--
		return true;
		}
		prev = prev->next;
	}
	return false;
}

遍历

void show_list(List* list)
{
for(Node* node=list->head;NULL != node;node->next)
	{
	printf("%d ",node->data);
	}//通过for循环让node从头部开始一直到尾部,让获取到尾结点后的NULL就停止然后换行
	printf("\n");
}

排序

//此函数用的是冒泡排序法(在主函数中别忘记遍历)
void sort_list(List* list)
{
for(Node* i = list->head;i->next != NULL;i=i->next)
	{
	for(Node* j = i->next;j->next!= NULL;j=j->next)//通过for循环获取i结点和j结点
		{
		if(i->data>j->data)
			{
				TYPE data = i->data;
				i->data = j->data;
				j->data = data;
			}//当获取到i结点的值比j的大时,将ij的值互换。通过ij两个指针将链表的值从小到大排序
		}
	}
}

逆序

//逆序就是从大到小排序,相当于上一个函数的反函数(逆序英文不会就用拼音代替啦)
//(在主函数中别忘了遍历)
void nixu(List* list)
{
Node* p1 = list->head;
Node* p2 = p1->next;
Node* p3 = NULL;//定义三个结点
list->tail = p1;//将尾结点指向p1
p1->next = NULL;//p1的next指向空
while(p2)
	{
	p3 = p2->next;
	p2->next = p1;
	p1 = p2;
	p2 = p3;
	}//通过while循环将p1p2p3的值逆序排列
	list->head = p1;
}

以上就是我最近学习链表的内容以及心得,欢迎指出错误和优化代码
谢谢

猜你喜欢

转载自blog.csdn.net/weixin_45050225/article/details/95750555
今日推荐