链表(C++版)

本文详细介绍了如何在C++中使用结构体ListNode实现链表的基本操作,包括链表的输出、尾部和头部插入、查找元素、删除节点以及链表的销毁。通过test_insert、test_find、test_erase和test_pop_and_push函数展示了这些功能的应用。
摘要由CSDN通过智能技术生成
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;

struct ListNode                     // 定义链表节点
{
	int data;                       // 存放节点数据
	ListNode* next;                 // 存放下一个节点的地址,以此连接各个节点,最后一个节点的next指针为NULL
};


void Listprintf(ListNode* phead)    // 定义链表输出函数   参数为*phead
{
	ListNode* cur=phead;            // *cur指向头节点phead
	while (cur != NULL)             //  当前节点非空
	{
		cout << cur->data << "->";  // 输出当前节点值和箭头符号
		cur = cur->next;            // 当前节点指向下一节点  
	}
	cout << "NULL" << endl;			// 输出NULL表示链表结束
}

void Listpushback(ListNode** pphead, int x)       // 尾部插入节点函数 二级指针(指向一个指针的指针)  
{
	ListNode* newnode = new ListNode{ x, NULL };  // 创建新节点
	if (*pphead == NULL)                    // 如果链表为空,则将新节点赋给pphead指针
	{
		*pphead = newnode;
	}
	else                                    // 如果*pphead指针指向非空,那么*tail = *pphead
	{
		ListNode* tail =  *pphead;			// 定义指针tail指向链表头
		while(tail->next != NULL)  // // 找到尾部节点,当tail的next属性值为非空时,循环继续
		{
			tail = tail->next;     // tail的值== tail -> next 指向next
		}
		tail->next = newnode;      // 此时的tail已经是尾部节点  在尾部节点后插入新节点
        //  意思是   *a = *p; a = b; b = c 
	}
}

void Listpushfront(ListNode** pphead, int x)     	// 头节点插入函数
{
	ListNode* newnode = new ListNode{ x, NULL }; 	// 创建新节点 
	newnode->next = *pphead;					    // 新节点的next指向当前头节点
	*pphead = newnode;							    // 更新头节点为新节点
}

//尾删
void Listpopback(ListNode** pphead)               // 尾节点删除函数
{
	if (*pphead == NULL)                          // 如果链表为空,则直接返回
	{
		return;
	}
	if ((*pphead)->next == NULL)                  // 如果链表只有一个节点
	{
		delete(*pphead);						// 删除头节点
		*pphead = NULL;							// 将头节点置为空
	}
	else                                        // 非空
	{
		ListNode* tail = *pphead;               // 定义指针tail指向链表头
		ListNode* prev = NULL;
		while (tail->next)                      // 当tail的下一个值非空时
		{										// 找到尾部节点和尾部节点的前一个节点
			prev = tail;                        // prev = tail 当前的地址 用于记录当前值的地址
			tail = tail->next;                  // tail指向下一个值的地址
		}
		delete(tail);                           // 删除尾部节点  删除tail也就是删除了*pphead
		tail = NULL;							// 将尾部节点置为空
		prev->next = NULL;						// 更新尾部节点的前一个节点的next指针为NULL
	}
}

//头删
void Listpopfront(ListNode** pphead)
{
	if (*pphead == NULL)  // 如果链表为空,则直接返回
	{
		return;
	}
	else
	{
		ListNode* newnode = (*pphead)->next;  //  // 定义指针newnode指向头节点的下一个节点
		delete(*pphead);	// 删除头节点
		*pphead = newnode;	// 更新头节点为下一个节点
	}
}

//查找元素,返回值是地址
ListNode* Listfind(ListNode* phead, int x)
{
	ListNode* cur = phead;  		// 定义指针cur指向链表头
	while (cur)						// 遍历链表
	{
		if (cur->data == x)			// 找到指定元素
		{
			return cur;				// 返回当前节点地址
		}
		else
		{
			cur = cur->next;		// 继续遍历下一个节点
		}
	}
	return NULL;					// 若未找到指定元素,则返回NULL
}
//插入元素,在pos的前一个位置插入
//配合Listfind使用,具体使用见test_insert函数
void Listinsert(ListNode** phead, ListNode* pos, int x)
{
	ListNode* newnode = new ListNode{ x,NULL }; // 创建新节点
	if (*phead == pos)                          // 如果pos是头节点
	{
		newnode->next = (*phead);              // 将新节点插入到头部
		*phead = newnode;
	}
	else									   // 否则,找到pos的前一个节点posprev
	{
		ListNode* posprev = *phead;
		while (posprev->next != pos)
		{
			posprev = posprev->next;
		}
		// 修改指针使得新节点插入到posprev和pos之间
		posprev->next = newnode;
		newnode->next = pos;
	}
}

//单链表并不适合在前一个位置插入,因为运算较麻烦,会损失效率
//包括c++中为单链表提供的库函数也只有一个insert_after而没有前一个位置插入
//在后一个位置插入相对简单
void Listinsert_after(ListNode** phead, ListNode* pos, int x)
{
	ListNode* newnode = new ListNode{ x,NULL }; // 创建新节点
	newnode->next = pos->next; // 修改指针使得新节点插入到pos的后面
	pos->next = newnode;
}

//删除指定位置的节点
void Listerase(ListNode** pphead, ListNode* pos) // 需要给定链表头指针和目标节点pos
{
	if (*pphead == pos) // 如果要删除的是头节点
	{
		*pphead = pos->next; // 更新头指针为头节点的下一个节点
		delete(pos);		// 释放节点内存
	}
	else
	{   // 否则,找到目标节点的前一个节点prev
		ListNode* prev = *pphead;
		while (prev->next!=pos)
		{
			prev = prev->next;
		}
		// 修改指针使得prev指向pos的下一个节点,然后释放pos节点的内存
		prev->next = pos->next;
		delete(pos);
	}
}

// 释放链表占用的内存
void Listdestory(ListNode** pphead) // 需要给定链表头指针
{
	ListNode* cur = *pphead;
	while(cur) // 遍历链表,释放每个节点的内存
	{
		ListNode* next = cur->next;
		delete(cur);
		cur = next;
	}// 将头指针置为空
	*pphead = NULL;
}







void test_insert()
{
	ListNode* phead = NULL;
	Listpushback(&phead, 1);
	Listpushback(&phead, 2);
	Listpushback(&phead, 3);
	Listprintf(phead);
	ListNode* pos = Listfind(phead, 2);
	if (pos != NULL)
	{
		Listinsert(&phead, pos, 20);
	}
	Listprintf(phead);
	pos = Listfind(phead, 2);
	if (pos != NULL)
	{
		Listinsert_after(&phead, pos, 20);
	}
	Listprintf(phead);
	Listdestory(&phead);
}
void test_find()
{
	ListNode* phead = NULL;
	Listpushback(&phead, 1);
	Listpushback(&phead, 2);
	Listpushback(&phead, 3);
	Listprintf(phead);
	ListNode* pos = Listfind(phead, 2);
	if (pos != NULL)
	{
		pos->data = 20;//Listfind不仅能查找,也能借此修改,这也是函数返回地址的原因
	}
	Listprintf(phead);
	Listdestory(&phead);
}
void test_erase()
{
	ListNode* phead = NULL;
	Listpushback(&phead, 1);
	Listpushback(&phead, 2);
	Listpushback(&phead, 3);
	Listprintf(phead);
	ListNode* pos = Listfind(phead, 2);
	if (pos != NULL)
	{
		Listerase(&phead, pos);
	}
	Listprintf(phead);
	Listdestory(&phead);
}
void test_pop_and_push()
{
	ListNode* phead = NULL;
	Listpushback(&phead, 1);
	Listpushback(&phead, 2);
	Listpushback(&phead, 3);
	Listprintf(phead);
	Listpushfront(&phead, 1);
	Listpushfront(&phead, 2);
	Listpushfront(&phead, 3);
	Listprintf(phead);
	Listpopback(&phead);
	Listpopfront(&phead);
	Listprintf(phead);
	Listdestory(&phead);
}

int main()
{
	test_pop_and_push();cout<< "------------" << endl;
	test_find();cout<< "------------" << endl;
	test_insert();cout<< "------------" << endl;
	test_erase();cout<< "------------" << endl;
	return 0;
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值