C++数据结构线性表的顺序存储之单链表(含有完整代码)

线性表的顺序存储

链表简介

用链式存储的方式实现的线性表称为链表。
链表又可以分为单链表,双链表,循环链表,静态链表。
节点:每个 存储数据元素的内存空间被称为一个节点。
单链表中,每个节点都包含数据域和指针域。
头结点(哨兵节点)始终位于任何节点之前。
不带头结点的单链表:初始化时不创建任何节点
不带头节点的单链表在编写基本操作的代码(插入、删除等)时更加繁琐,往往需要对第一个或者最后一个数据单独处理。
带头节点的单链表:在初始化时要优先头节点
头结点不存放任何实际元素数据
如果频繁地向单链表末尾插入新节点,可以考虑插入一个表尾指针。该转正在单链表为空的时候指向头结点。
在单链表非空时要注意保持其指向最后一个节点。

特点总结
扩容方便
插入和删除节点方便
链表比数组更适合插入,删除操作频繁的场景。
存放后继指针消耗额外内存空间。体现了利用空间换时间
对于内存紧张的硬件设备,需要考虑单链表是否合适
内存空间不连续所以无法随机访问链表中的元素。
代码书写测试建议
多通过画图来理清逻辑
链表为空的时候,测试代码能否正常工作。
链表只有一个元素时,测试代码工作情况。
分别测试处理链表第一个节点和最后一个节点能否正常工作。
设置端点对代码进行调试。

实现代码

#include <iostream>
using namespace std;
template <typename T>//T代表数据元素的类型
struct Node
{
	T data;//数据域,存放数据元素
	Node <T>* next;//指针域,指向下一个同类型的节点
};
//单链表的定义
template <typename T>
class LinkList
{
public:
	LinkList();//构造函数
	~LinkList();//析构函数
	bool ListInsert(int i, const T& e);//在第I个位置插入
	bool ListDelete(int i);//在第I个位置删除
	bool GetElem(int i, T& e);//获取第I个位置的元素
	int LocateElem(const T& e);//按元素查找其在单链表第一次出现的的位置
	void DisplayList();//输出单链表中的所有元素
	int ListLength();//输出单链表的长度
	bool Empty();//判断单链表是否为空
	void ReverseDataList();//翻转单链表数据
	void ReverseList();//翻转单链表
	bool InsertPriorNode(Node<T>* pcurr, const T& e);
	bool ListDelete();
	//在链表某个节点之前插入节点
private:
		Node<T>* m_head;//头指针(指向链表第一个节点的指针)
		int m_length;//单链表当前长度
};
//通过构造函数对单链表进行初始化
template <typename T>
LinkList<T>::LinkList()
{
	m_head = new Node<T>;//先创建一个头结点
	m_head->next = nullptr;
	m_length = 0;//头结点不计入单链表的长度
	/*
	如果不带头结点的初始化
	m_head=nullptr;
	m_length=0;          
	*/
}
//单链表元素插入操作(在第i个位置插入指定元素e)
template <typename T>
bool LinkList<T>::ListInsert(int i, const T& e)
{
	//判断插入位置是否合法
	if (i<1 || i>(m_length+1))
	{
		cout << "元素插入位置不合法!" << endl;
		return false;
	}
	Node<T>* p_curr = m_head;
	//for循环用于找到第i-1个节点
	if (m_length == 0)
	{
		Node<T>* node = new Node<T>;//(1)
		node->data = e;//(2)
		node->next = nullptr;//让新节点连上后续节点
		p_curr->next = node;//让当前位置连上新节点
		cout << "插入位置为" << i << "成功在位置为" << i << "插入元素" << e << "!" << endl;
		m_length++;//实际表长加一
	}
	else
	{
		if (m_length >= i)
		{
			for (int j = 0; j < (i - 1); ++j)//j从0开始,表示p_curr一开始指向第0个节点
			{
				p_curr = p_curr->next;//一直找到需要插入的位置
				cout << "寻找到第" << j + 1 << "个节点" << endl;
				cout << "-------laoding-------" << endl;
			}
			Node<T>* node = new Node<T>;//(1)
			node->data = e;//(2)
			node->next = p_curr->next;//让新节点连上后续节点
			p_curr->next = node;//让当前位置连上新节点
			cout << "m_length=" << m_length << "插入位置为" << i << "成功在位置为" << i << "插入元素" << e << "!" << endl;
			m_length++;//实际表长加一
			cout << "-----插入后链表为-----" << endl;
			Node<T>* p_curr1 = m_head->next;
			for (int j = 1; j < m_length+1; ++j)//j从0开始,表示p_curr一开始指向第0个节点
			{

				cout << p_curr1->data << " ";
				p_curr1 = p_curr1->next;
			}
			cout << endl;
		}
		else
		{
			for (int j = 0; j < (i - 1); ++j)//j从0开始,表示p_curr一开始指向第0个节点
			{
				p_curr = p_curr->next;//一直找到需要插入的位置
				cout << "寻找到第" << j+1 << "个节点" << endl;
				cout << "-------laoding-------" << endl;
			}
			Node<T>* node = new Node<T>;//(1)
			node->data = e;//(2)
			node->next = nullptr;//让新节点连上空指针
			p_curr->next = node;//让当前位置连上新节点
			cout << "m_length=" << m_length << "插入位置为" << i << "成功在位置为" << i << "插入元素" << e << "!" << endl;
			m_length++;//实际表长加一
			cout << "-----插入后链表为-----" << endl;
			Node<T>* p_curr2 = m_head;
			Node<T>* p_curr1 = p_curr2->next;
			for (int j = 1; j < m_length+1; ++j)//j从0开始,表示p_curr一开始指向第0个节点
			{

				cout << p_curr1->data << " ";
				p_curr1 = p_curr1->next;
			}
			cout << endl;
		}
	}
}
//单链表元素插入操作(在第i个位置插入指定元素e)(不带头结点)
/* 
template <typename T>
bool LinkList<T>::ListInsert(int i,const T& e)
{
   //判断插入位置i是否合法
   if(i<1||i>(m_length+1))
   {
      cout<<"元素"<<e<<"插入位置"<<i<<"不合法"<<endl;
	  return false;
   }
   if(i==1)
   {
       Node<T>* node= new Node<T>;
	   node->data=e;
	   node->netx=m_head;
	   m_head=node;//头指针指向插入的第一个元素
	   cout<<"成功在位置为"<<i<<"处插入元素"<<e<<"!"<<endl;
	   m_length++;
	   return true;
   }
   else
   {
      Node<T>* p_curr=m_head;
      for(int j=0;j<(i-1);++j)
	  {
	      p_curr=p_curr->next;
	  }
	  Node<T>* node=new Node<T>;
	  node->data=e;
	  if((p_curr)!=nullptr)
	  {
	      node->next=p_curr->next;
	      p_curr->next=node;
	  }
	  else
	  {
	      node->next=nullptr;
	      p_curr->next=node;
	  }
   }

}
*/
//单链表扫描功能
template <typename T>
void LinkList<T>::DisplayList()
{
	Node<T>* p_curr = m_head->next;
	for (int j = 1; j < m_length+1; ++j)//j从0开始,表示p_curr一开始指向第0个节点
	{

		cout << p_curr->data << " ";
		p_curr = p_curr->next;
	}
	cout << endl;
}
template <typename T>
bool LinkList<T>::InsertPriorNode(Node<T>* pcurr, const T& e)
{
	//在节点pcurr之前插入新节点,新节点的数据域为e
	Node<T>* p_curr = new Node<T>;
	p_curr->data = e;
	p_curr->next = pcurr->next;
	pcurr->next = p_curr;
}
template <typename T>
bool LinkList<T>::ListDelete(int i)
{
	if (m_length < 1)
	{
		cout << "当前单链表为空,不能删除任何数据!" << endl;
		return false;
	}
	Node<T>* p_curr=m_head;
	if (i<1 || i>m_length)
	{
		cout << "删除位置不合法!" << endl;
		return false;
	}
	if (i >= 1 && i < m_length)
	{
		for (int j = 0; j < (i - 1); ++j)
		{
			p_curr = p_curr->next;
		}
		Node<T>* node;
		node = p_curr->next;
		p_curr->next = node->next;
		cout << "成功删除位置为" << i << "的元素" << node->data << "!" << endl;
		delete node;
		m_length--;//表长减一
		return true;
	}
	else
	{
		for (int j = 0; j < (i - 1); ++j)
		{
			p_curr = p_curr->next;
		}
		Node<T>* node;
		node = p_curr->next;
		p_curr->next = nullptr;
		cout << "成功删除位置为" << i << "的元素" << node->data << "!" << endl;
		delete node;
		m_length--;//表长减一
		return true;
	}
}
template <typename T>
bool LinkList<T>::GetElem(int i,  T& e)//获取第i个位置的元素值
{
	if (i<1 || i>m_length)
	{
		cout << "该位置不合法" << endl;
		return false;
	}
	Node<T>* p_curr = m_head;
	for (int j = 0; j < i; j++)
	{
		p_curr = p_curr->next;
	}
	e = p_curr->data;
	cout << "第" << i << "位元素的值为" << e << endl;
	return true;
}
template <typename T>
int LinkList<T>::LocateElem(const T& e)
{
	int k = 0;
	Node<T>* p_curr = m_head;
	for (int i = 0; i < m_length-1; i++)
	{
		p_curr = p_curr->next;
		if ((p_curr->data) == e)
		{
			++k;
			return k;
		}
		else
		{
			++k;
		}
	}
	if (((p_curr->next)->data) != e)
	{
		cout << "该单链表中不存在值为" << e << "的元素!" << endl;
		return 0;
	}
	else
	{
		return m_length;
	}
}
template <typename T>
int LinkList<T>::ListLength()
{
	return m_length;
}
template <typename T>
bool LinkList<T>::Empty()
{
	if(m_length==0)
	{ 
		return true;
	}
	else
	{
		return false;
	}
}
template <typename T>
void LinkList<T>::ReverseDataList()//翻转单链表数据
{
	int k = m_length / 2;
	for (int i = 1; i <= k; i++)
	{
		Node<T>* p_currL = m_head;
		Node<T>* p_currR = m_head;
		for (int j = 1; j <= m_length - i; j++)
		{
			if (j <= i)
			{
				p_currL = p_currL->next;
			}
			p_currR = p_currR->next;
		}
		T a = p_currL->data;
		p_currL->data = p_currR->data;
		p_currL->data = a;
		p_currL = m_head;
		p_currR = m_head;
	}
}
template <typename T>
void LinkList<T>::ReverseList()
{
	if (m_length <= 1)
	{
		return;
	}
	Node<T>* pothersjd = m_head->next -> next;//指向第二个节点开始的后续节点
	m_head->next->next = nullptr;
	Node<T>* ptmp;
	while (pothersjd != nullptr)
	{
		ptmp = pothersjd;
		pothersjd = pothersjd->next;
		ptmp->next = m_head->next;
		m_head->next = ptmp;
	}
}
template <typename T>
LinkList<T>::~LinkList()//释放单链表中的元素
{
	Node<T>* pnode = m_head->next;
	Node<T>* ptmp;
	while (pnode != nullptr)
	{
		ptmp = pnode;
		pnode = pnode->next;
		m_head->next = pnode;//可有可无
		delete ptmp;
	}
	delete m_head;//释放头结点
}
int main()
{
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//检测内存泄漏
	LinkList<int> slinkobj;
	slinkobj.ListInsert(1, 12);
	slinkobj.ListInsert(1, 24);
	slinkobj.ListInsert(3, 38);
	slinkobj.ListInsert(2, 139);
	slinkobj.ListInsert(3, 100);
	slinkobj.ListDelete(4);
	slinkobj.DisplayList();
	int k=0;
	slinkobj.GetElem(2, k);
	k=slinkobj.LocateElem(12);
	cout << k << endl;
	slinkobj.ReverseList();
	slinkobj.DisplayList();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值