单链表的实现

单链表的实现

1.链表的概念及结构

概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链
接次序实现的 。
结构:
在这里插入图片描述
注意:

  1. 从图中可以看出来,链式结构在逻辑上是连续的,但是在物理上不一定连续。
  2. 链表中的节点一般都是在堆上申请出来的。

2.链表的分类

单项或者双向链表:
在这里插入图片描述
带头或者不带头:
在这里插入图片描述
循环或者非循环:
在这里插入图片描述

3.单链表定义

typedef int listDataType;

//定义节点类型
typedef struct listNode
{
    listDataType data;
    struct listNode* next;
}listNode;

typedef listNode* list;

在这里插入图片描述

4.接口的实现

//函数定义
listNode* buyNode(listDataType val);//动态申请一个链表的节点
void listInit(list* ls);//链表的初始化
void listPushBack(list* ls, listDataType val);//尾插一个数据
void listPopBack(list* ls);//尾删一个数据
void listPushFront(list* ls, listDataType val);//头插一个数据
void listPopFront(list* ls);//头删一个数据
void listInsertAfter(listNode* cur, listDataType val);//在pos位置之后插入一个数据
void listEraserAfter(listNode* cur);//在pos位置之后删除一个数据
listNode* listFind(list ls, listDataType val);//按值查找
void listInsert(list* ls, listDataType val);//按值插入
void listErase(list* ls, listDataType val);//按值删除
void listSort(list* ls);//链表排序
void listReverse(list* ls);//链表逆置
void printfList(list ls);//打印链表
void listDestory(list* ls);//摧毁链表
动态申请一个链表的节点
  1. 动态申请内存,创建新的节点。
  2. 将新节点的数据存放到data中。
  3. 节点的next指针置空。
listNode* buyNode(listDataType val)
{
	listNode* newNode = (listNode*)malloc(sizeof(listNode));
	assert(newNode);
	newNode->data = val;
	newNOde->next = NULL;

	return newNode;
}
链表的初始化
  1. 指向第一个节点的指针置空
void listInit(list* ls)
{
	*ls = NULL;
}
尾插一个数据
  1. 申请一个新的节点。
  2. 判断是否是第一个元素,如果是,则头结点的指针指向新的节点。
  3. 如果不是第一个元素,则找到最后一个元素后,在最后一个个元素的后面插入新的节点。
void listPushBack(list* ls, listDataType val)
{
	listNode* newNode = buyNode(val);

	if(*ls == NULL)
	{
		*ls = newNOde;
		return;
	}
	listNode* p = *ls;
	while(p->next != NULL)
	{
		p=p->nxt;
	}
	p->next = newNode;
}
尾删一个数据
  1. 判断链表是否有数据,如果不是空链表,则开始进行删除。
  2. 创建两个节点类型变量tail和prev,tail初始值等于第一个节点,prev等于空,分别向后每次移动一个位置,保存的是最后一个元素和倒数第二个元素。
  3. 如果prev为NULL,说明链表只有一个元素,则删除第一个元素。
  4. 如果prev不等于NULL,prev的next为空,并释放tail的空间。
void listPopBack(list* ls)
{
	if(*ls == NULL)
	{
		return;
	}
	listNode* tail = *ls;
	listNode* prev = NULL;
	while(tail->next != NULL)
	{
		prev = tail;
		tail =t ail->next;
	}
	//删除的是第一个元素
	if(prev == NULL)
	{
		*ls = NULL;
	}
	//不只有一个元素
	else
	{
		prev->next = NULL;
	}
	free(tail);
}
头插一个数据
  1. 创建新的节点。
  2. 新节点的next等于链表的第一个节点。
  3. 第一个节点的指针指向新的节点
void listPushFront(list* ls, listDataType val)
{
    listNode* node = buyNode(val);
    node->next = *ls;
    *ls = node;
}

头删一个数据
  1. 判断链表是否为空。
  2. 创建一个节点变量p 保存第一个节点的位置。
  3. 把指向第一个节点的指针指向p的next。
  4. 释放p的空间。
void listPopFront(list* ls)
{
    listNode* p = *ls;
    if (*ls == NULL)
    {
        return;
    }
    *ls = p->next;
    free(p);
}
在pos位置之后插入一个数据
  1. 创建一个新的节点。
  2. pos的next等于新的节点
  3. 新节点的next等于pos的下一个节点。
void listInsertAfter(listNode* cur, listDataType val)
{
    listNode* node = buyNode(val);
    node->next = cur->next;
    cur->next = node;
}
在pos位置之后删除一个数据
  1. 判断链表是否为空 。
  2. 创建一个节点类型变量next保存pos位置的下一个位置。
  3. pos的下一个节点等于next节点的下一个节点。
  4. 释放next的空间。
void listEraserAfter(listNode* cur)
{
    listNode* next = cur->next;
    if (next == NULL)
    {
        return;
    }
    cur->next = next->next;
    free(next);
}
按值查找
  1. 遍历整个链表,找到与val值相等的节点并返回。
listNode* listFind(list ls, listDataType val)
{
    if (ls == NULL )
        return NULL;
    //从第一个节点开始遍历
    listNode* cur = ls;
    while (cur!=NULL) 
    {
        if (cur->data == val) 
        {
            return cur;
        }
        cur = cur->next;
    }
    return NULL;
}
按值插入
  1. 创建新的节点。
  2. 如果是空链表,则指向第一个节点的指针指向新的节点。
  3. 不是空链表的情况下,如果要插入的数据比第一个节点的数据还小,进行头插。
  4. 在其他位置进行插入。
void listInsert(list* ls, listDataType val)
{
    listNode* newNode = buyNode(val);
    //空链表
    if(*ls == NULL)
    {
    	*ls = newNode;
    	return;
    }
    //在第一个位置进行插入
    if(val < (*ls)->data)
    {
    	newNode->next = *ls;
    	*ls = newNode;
    	return;
    }
    //在其他位置进行插入
    listNode* p = *ls;
    while(p->next != NULL && p->next->data < val)
    {
    	p=p->next;
    }
    newNode->next = p->next;
    p->next = newNode;
}
按值删除
  1. 判断链表是否有数据,如果不是空链表,则开始进行删除。
  2. 创建两个节点类型变量tail和prev,tail初始值等于第一个节点,prev等于空,分别向后每次移动一个位置,直到找到val的节点和他前一个节点。
  3. 如果prev为NULL,说明删除的是第一个元素。
  4. 如果prev不等于NULL,prev的next指向tail的next,并释放tail的空间。
void ListErase(List *plist, ElemType key)
{
	ListNode *tail = *plist;
	ListNode *prev = NULL;
	if(tail == NULL)
	{
		return}
	while(tail != NULL && tail->data != val)
	{
		prev = tail ;
		tail = tail->next;
	}
	if(prev == NULL)
	{
		*ls = NULL;
	}
	else
	{
		prev->next = tail->next;
	}
	free(tail);
}
链表排序
  1. 如果链表为空或者只有一个数据,则不进行排序。
  2. 断开链表在这里插入图片描述
  3. 将断开后的链表依次进行按值插入。
void listSort(list* ls)
{
    if (*ls == NULL || (*ls)->next == NULL)
    {
        return;
    }
    listNode* p = NULL;
    //断开链表
    p = (*ls)->next;
    *ls)->next = NULL;

	//按值插入
	while(p != NULL)
	{
		listNode* q = p->next;
		//比第一个位置的值还小
		if(p->data < (*ls)->data)
		{
			p->next = (*ls)->next;
			*ls = p;
		}
		//在其他位置插入
		else
		{
			listNode* prev = *ls;
			while(prev->next != NULL && prev->next->data < p->data)
			{
				prev = prev->next;
			}
			p->next = prev->next;
			prev->next = p;
		}
		p=q;
	}
}
链表逆置
  1. 断开链表。
  2. 断开后的链表依次进行头插。
void listReverse(list* ls)
{
    if ((*ls) == NULL || (*ls)->next == NULL)
    {
        return;
    }
    //断开链表
    listNode* p = (*ls)->next;
    (*ls)->next = NULL;
	while(p != NULL)
	{
		//头插节点
        listNode* q = p->next;
        p->next = *ls;
        *ls = p;

		p = q;
	}
}
链表打印
void printfList(list ls)
{
    listNode* node = ls;
    while (node != NULL)
    {
        printf("%d ", node->data);
        node = node->next;
    }
    printf("\n");
}
链表销毁
void listDestory(list* ls)
{
    listNode* p = NULL;
    while (*ls != NULL)
    {
        p = *ls;
        *ls = p->next;
        free(p);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值