C++实现带头结点单链表

单链表属于基本数据结构中的线性结构,它应用于很多数据结构中,例如栈,队列等,作用广泛。在数据结构中我们习惯把关于单链表的一系列操作制作为一个ADT(Abstract Data Type)使用,在C++中把它封装为一个类,使用起来更是方便。

关于单链表的操作包括插入(包括头插和尾插)、删除、查找、检查是否有环、环的长度、环的入口等操作。以下就是我的代码实现:
每个结点的数据类型应该是一个结构体类型:
struct Node
{
	Node(int data=0)
	{
		_data = data;
		_pnext = NULL;
	}
	int _data;
	Node *_pnext;

单链表类的定义:


class LinkList
{
public:
	LinkList()
	{
		_head = new Node;
		cout<<"LinkList()"<<endl;
	}
	~LinkList()
	{
		if (_head == NULL)
		{
			return;
		}
		if (isLoop())
		{
			Node *tmp = _head->_pnext;
			Node *p = NULL;
			while (tmp != getFirstLoopNode())
			{	
				tmp = tmp->_pnext;	
			}
			tmp->_pnext = NULL;
		}
		Node *tmp = _head->_pnext;
		Node *p = NULL;
		while (tmp != NULL)
		{
			p = tmp;
			tmp = tmp->_pnext;
			delete p;	
		}
		delete _head;
		cout<<"~LinkList()"<<endl;
	}

	void insertHead(int data)
	{
		Node *tmp = new Node(data);
		tmp->_pnext = _head->_pnext;
		_head->_pnext = tmp;
	}

	void insertTail(int data)
	{
		Node *tmp = _head->_pnext;
		while (tmp->_pnext != NULL)
		{
			tmp = tmp->_pnext;
		}
		tmp->_pnext = new Node(data);
		tmp->_pnext->_pnext = NULL;
	}

	void deleteData(int data)
	{
		Node *tmp = _head->_pnext;
		Node *p = _head;
		while (tmp->_data != data && tmp->_pnext != NULL)
		{
			p = tmp;
			tmp = tmp->_pnext;
		}
		p->_pnext = tmp->_pnext;
		delete tmp;
	}
	void show()
	{
		Node *tmp = _head->_pnext;
		while (tmp != NULL)
		{
			cout<<tmp->_data<<" ";
			tmp = tmp->_pnext;
		}
		cout<<endl;
	}
	//是否有环
	bool isLoop()
	{
		Node*fast = _head;
		Node*slow = _head;
		while (fast != NULL && fast->_pnext != NULL)
		{
			fast = fast->_pnext->_pnext;
			slow = slow->_pnext;
			if (fast == slow)
			{
				return true;
			}
		}
		return false;
	}
	void creat_loop()//创建有环链表
	{
		Node *tmp = _head->_pnext;
		while (tmp->_pnext != NULL)
		{
			tmp = tmp->_pnext;
		}
		tmp->_pnext = _head->_pnext;
	}
	//获取单链表环的第一个节点
	Node* getFirstLoopNode()
	{
		Node *fast = _head;
		Node *slow = _head;
		while (fast != NULL && fast->_pnext != NULL)//快指针走的步数是慢指针走的步数的两倍
		{
			fast = fast->_pnext->_pnext;
			slow = slow->_pnext;
			if (fast == slow)
			{
				break;
			}
		}
		slow = _head;
		while (slow != fast)
		{
			slow = slow->_pnext;
		}
		return slow;
	}
	//获取环的长度
	int getLoopLength()
	{
		
		Node *fast = _head;
		Node *slow = _head;
		while (fast != NULL && fast->_pnext != NULL)
		{
			fast = fast->_pnext->_pnext;
			slow = slow->_pnext;
			if (fast == slow)
			{
				break;
			}
		}
		slow = slow->_pnext;
		int count = 1;
		while (slow != fast)
		{
			slow = slow->_pnext;
			count++;
		}
		return count;
	}
private:
	Node *_head;
};
int main()
{
LinkList list;
for (int i=0;i<4;i++)
{
list.insertHead(rand()%10);
}
list.show();
for (int i=1;i<6;i++)
{
list.insertTail(i*10);
}
list.deleteData(0);
list.show();
list.creat_loop();
if (list.isLoop())
{
cout<<"have a loop"<<endl;
cout<<"loop entrance:"<<list.getFirstLoopNode()->_data<<endl;
cout<<"loop length:"<<list.getLoopLength()<<endl;
}
return 0;
}      

判断链表是否有环,通常的办法就是使用快慢指针,快慢指针初始时指向同一个位置,这里指向头结点(fast = _head;slow = _head);快指针每次向前走两步(fast = fast->_pnext->_pnext;),慢指针每次走一步( slow = slow->_pnext;);当快指针遇到慢指针时,说明该链表有环。
      计算环的长度,在环上相遇后,记录第一次相遇点为fast=slow,添加计数器count=0;fast不动,slow每次走一步,count++,等到fast==slow时,count的值就是环的长度。
      判断环的入口,假设头结点距离环的入口的距离是len,在环上相遇时,假设slow走了S步,则fast走了2S步,并且2S=S+len,即S=len,所以当fast和slow相遇时,slow从头结点出发,当遇到fast时的位置就是环的入口结点。
      上述代码中由于创建了有环的链表,所以在析构函数中添加了有环链表的析构过程,相对来说,这个链表还不算完整,比如对有环链表的插入结点、删除结点以及打印结点信息的方法都未实现,原理上与析构的过程其实是一致的,基本原理懂了,一切都so easy了。*^_^*
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值