【数据结构】单链表

一、概念

1、链表:逻辑上连续,物理存储不连续的一种线性表的实现,链表具有唯一的起始和唯一的结尾

2、单链表:前一个结点除了存储元素值外,还必须存储下一个结点的地址

                    除了最后一个元素外,每一个结点都有一个直接后继 

3、头指针:链表中第一个结点的存储位置叫做头指针

4、头结点:在单链表的第一个结点前附设一个结点,称为头结点

                    头结点的数据域可以不存储任何信息,头结点的指针域存储指向第一个结点的指针

  •  头指针与头结点的异同
头指针头结点
  • 头指针是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针
  • 头结点是为了操作的统一和方便,放在第一元素的结点之前,其数据域一般无意义
  • 头指针具有标识作用,所以经常用头指针冠以链表的名字
  • 有了头结点,对在第一元素结点前插入结点和删除第一结点,其操作与其他结点的操作就统一了
  • 无论链表是否为空,头指针均不能为空,头指针是链表的必要元素
  • 头结点不一定是链表的必要元素

二、单链表(带头结点)

 

1、存储结构

typedef int ElemType;

typedef struct Node
{
    ElemType data;       //数据域:存储数据
	struct Node* next;   //指针域:存储下一个结点的地址
}Node,*pList;

2、初始化

void init(pList phead)
{
	if (phead == nullptr)
	{
		exit(0);
	}
	phead->next = nullptr;
}

3、插入

  • 单链表中插入一个结点,首先先要购买一个结点作为要插入的结点

购买结点

Node* buyNode(ElemType val)
{
   Node* pnewnode = (Node*)malloc(sizeof(Node));
   pnewnode->data = val;
   pnewnode->next = nullptr;
   return pnewnode;
}
  • 插入时要注意语句的先后顺序

(先将插入结点的后继指向插入结点前一个结点的后继,再将前一个结点的后继指向插入结点)

(1)头插

int insertHead(pList phead, ElemType val)
{
	/*
	    return insertPos(phead, 0, val);
	*/
	//一般来说都要先进行判空
	Node* pnewnode = buyNode(val);//先购买结点
	pnewnode->next = phead->next;//新结点的指针域指向头结点之后的数据
	phead->next = pnewnode;  //头结点的指针域指向新结点
	return 1; //成功
}

(2)尾插

int insertTali(pList phead, ElemType val)//新结点放到最后一个结点之后--》先找尾部结点
{
	Node* pnewnode = buyNode(val);
	Node* ptail = phead;
	while (ptail->next != NULL)
	{
		ptail = ptail->next;
	}
	ptail->next = pnewnode;//将新结点的地址写到尾结点的指针域(尾结点指向的新的结点)
	return 1;
}

(3)按位置插入

对单链表进行按位置插入,需要获取单链表的长度来判断插入位置是否有效

  • 获取长度
    int getLength(pList phead)
    {
    	int count = 0;
    	Node* pCur = phead;
    	while (pCur != nullptr)
    	{
    		count++;
    		pCur = pCur->next;
    	}
    	return count;
    }
    int insertPos(pList phead, int pos, ElemType val)
    {
    	Node* pnewnode = buyNode(val);
    	int i = 0;
    	Node* pfront = phead;
    	//判断位置是否合理
    	if (pos < 0 || pos > getLength(phead))
    	{
    		return 0;//失败,位置不合理非法
    	}
    	for (i; i < pos; i++)
    	{
    		pfront = pfront->next;//找到插入点之前的结点
    	}
    	pnewnode->next = pfront->next;
    	pfront->next = pnewnode;
    	return 1;
    }

    4、删除

单链表删除结点时需先判空,若链表为空,则不用删除

  • 判空

int empty(pList phead)
{
	return phead->next == nullptr ? 1 : 0;
}

(1)头删

int deleteHead(pList phead)
{
	/*
	    return deletePos(phead, 0);
	*/
	if (empty(phead))
	{
		return -1;
	}
    Node* pdel = phead->next;
	phead->next = pdel->next;
	free(pdel);
	return 1;
}

(2)尾删

int deleteTail(pList phead)
{
	Node* ptail2 = phead;
	Node* pdel = nullptr;
	if (empty(phead))
	{
		return -1;
	}
	while(ptail2->next != nullptr)//ptail2下一个结点存在
	{
		if (ptail2->next->next == nullptr)
		{
			break;
		}
		ptail2 = ptail2->next;//最后一个结点删除
	}
	pdel = ptail2->next;//pdel保存最后一个删除点
	ptail2->next = nullptr;
	free(pdel);
	return 1;
}

(3)按位置删除

int deletePos(pList phead, int pos)
{
	int i = 0;
	Node* pfront = phead;
	Node* pdel = nullptr;
	if (pos < 0 || pos >= getLength(phead))
	{
		return -1;
	}
	for (i; i < pos; i++)
	{
		pfront = pfront->next;
	}
	pdel = pfront->next;
	pfront->next = pdel->next;
	free(pdel);
	return 1;
}

5、打印

void Show(pList phead)
{
	Node* pCur = phead->next;//第一个数据结点
	while (pCur != nullptr)//数据结点存在
	{
		printf("%d  ", pCur->data);
		pCur = pCur->next;
	}
	printf("\n");
}

6、销毁

void destory(pList phead)
{
	Node* pCur = phead->next;//第一个数据结点
	Node* pNext = nullptr;
	while (pCur != nullptr)//当前结点存在
	{
		pNext = pCur->next;
		free(pCur);
		pCur = pNext;
	}	
	phead->next = nullptr;
}

主函数

#include <stdio.h>
#include "SeqList.h"

int main()
{
	Node head;
	int i = 0;
	init(&head);
	for (i; i < 5; i++)
	{
        insertHead(&head,i + 1);//5 4 3 2 1 
	}
	Show(&head);
	for (i=0; i < 5; i++)
	{
		insertTali(&head, i + 1);//5 4 3 2 1 1 2 3 4 5 
	}
	Show(&head);
	insertPos(&head, 6,100);
	Show(&head);

	deleteHead(&head);  //4 3 2 1 1 100 2 3 4 5
	Show(&head);
	deleteTail(&head);//4 3 2 1 1 100 2 3 4
	Show(&head);
	deletePos(&head, 2);//4 3 1 1 100 2 3 4
	Show(&head);
	destory(&head);
    return 0;
}

 

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值