数据结构之单链表简单操作

(一)单链表

单链表结构:数据域_data和指针域_pnext,其基本操作如下列代码所示,附有注释说明:

//单链表结构
typedef int ElemType;
typedef struct Node
{
	ElemType _data;
	struct Node* _pnext;
}Node,*PClist;


//购买节点
Node* BuyNode()
{
	Node* pnode = (Node*)malloc(sizeof(Node));
	assert(pnode != NULL);
	return pnode;
}
//释放节点
void FreeNode(Node* pnode)
{
	free(pnode);
}
//初始化链表  购买头结点
void Init_List(PClist plist)
{
	if(plist == NULL )
		return ;

	plist->_pnext = NULL;
}
//单链表头插
bool Insert_Head(PClist plist,ElemType key)
{
	if( plist == NULL )
		return false;
	Node* pnewNode = BuyNode();
	if(pnewNode == NULL)
		return false;
	//给新节点的数据域赋值
	pnewNode ->_data = key;
	//新节点的_pnext域指向头结点的_pnext
	pnewNode ->_pnext = plist->_pnext;
	//头结点的_pnext域指向新节点
	plist->_pnext = pnewNode;
	return true;
}
//单链表尾插
bool Insert_Tail(PClist plist,ElemType key)
{
	if( plist == NULL )
		return false;
	Node* p = plist;
	//先走到链表尾部
	for(p;p->_pnext != NULL;p= p->_pnext);
	//购买新节点
	Node* pnewNode = BuyNode();
	pnewNode->_data = key;
	//新节点的_pnext域指向p的_pnext域
	//p的_pnext域指向新节点
	pnewNode->_pnext = p->_pnext;
	p->_pnext = pnewNode;
	return true;
}
//查找某个值是否在链表中 并返回其节点
Node* Search(PClist plist,ElemType key)
{
	if(plist == NULL)
		return NULL;
	Node* p = plist->_pnext;
	for(;p != NULL ; p = p->_pnext)
	{
		if( p->_data == key)
		{
			return p;
		}
	}
	return NULL;
}
//查找某个值在单链表中的前驱
Node* Search_Prev(PClist plist,ElemType key)
{
	if(plist == NULL)
		return NULL;
	Node* p = plist;
	for(;p->_pnext != NULL ; p = p->_pnext)
	{
		if( p->_pnext->_data == key)
		{
			return p;
		}
	}
	return NULL;
}
//删除某个节点
//首先查找要删的节点是否在链表中
//如果存在则需要找到被删节点的前驱
//被删节点的前驱的_pnext域指向被删节点的后继
//最后free调要删的节点
bool Delete_Node(PClist plist,ElemType key)
{
	if(plist == NULL)
		return false;
	Node* p = Search(plist,key);
	if(p == NULL)
		return NULL;
	Node* q = Search_Prev(plist,key);
	if(q == NULL)
		return false;
	q->_pnext = p->_pnext;
	FreeNode(p);
	return true;
}
//统计链表长度
int GetLength(PClist plist)
{
	int len = 0;
	if(plist == NULL)
		return len;
	for(Node* p = plist->_pnext;p != NULL;p=p->_pnext)
	{
		len++;
	}
	return len ;
}
//判断链表是否为空
bool IsEmpty(PClist plist)
{
	return plist->_pnext == NULL;
}
//销毁链表
void Destroy(PClist plist)
{
	if(plist == NULL)
		return ;
	Node* p ;
	while(plist ->_pnext != NULL)
	{
		p = plist->_pnext;
		plist->_pnext = p->_pnext;
		free(p);
	}
}
//打印单链表
void Show(PClist plist)
{
	for(Node* p = plist->_pnext; p != NULL; p=p->_pnext)
	{
		printf("%d ",p->_data);
	}
	printf("\n");
}
//链表逆置
void Reserve(PClist plist)
{
	if(plist == NULL)
		return ;
	Node *p=plist->_pnext;//plist的下一个节点
	plist->_pnext=NULL;//将Plist指向的节点置为空
	Node *q=p;//plist的下一个节点
	while(p!=NULL)
	{
		q=p->_pnext;//保存P的所指向的下一节点
		p->_pnext=plist->_pnext;//p->next保存plist所指的节点;
		plist->_pnext=p;//plist保存p的地址
		p=q;//指针p往后跳;
	}
}

(二)常见链表面试题(部分,后面继续更新)

(1)判断链表是否有环

//判断链表是否有环
bool IsCircle(PClist plist)
{
	if(plist == NULL)
		return false;
	Node* low = plist;
	Node* fast = plist;

	while( low && fast -> _pnext)
	{
		low = low->_pnext;
		fast = fast->_pnext;
		if(fast ->_pnext !=  NULL)
		{
			fast = fast->_pnext;
		}
		if(fast == low)
		{
			return true;
		}
	}
	return false;
}

//测试用例
/*Node* p = Search(&head1,3);
	Node* q= Search(&head1,10);
	q->_pnext = p ;
	if(IsCircle(&head2))
	{
		cout<<"head2 list has circle"<<endl;
	}
	else
	{
		cout<<"head2 list has not circle"<<endl;
	}

	if(IsCircle(&head1))
	{
		cout<<"head1 list has circle"<<endl;
	}
	else
	{
		cout<<"head1 list has not circle"<<endl;
	}
	*/

(2)寻找环的入口地址

//找到环的入口地址 解法一
Node* Finde_Circle(PClist plist)
{	
	if(plist == NULL)
		return false;
	Node* low = plist;
	Node* fast = plist;

	while( low && fast -> _pnext)
	{
		low = low->_pnext;
		fast = fast->_pnext;
		if(fast ->_pnext !=  NULL)
		{
			fast = fast->_pnext;
		}
		if(fast == low)
		{
			break;
		}
	}
	fast = plist;
	while(fast ->_pnext && low->_pnext )
	{
		fast = fast->_pnext;
		low = low->_pnext;
		if(fast == low)
		{
			return low;
		}
	}
	return NULL;
}
//找到环的入口地址 解法二  不是最优
Node* Finde_Circle1(PClist plist)
{	
	if(plist == NULL)
		return false;
	Node* low = plist;
	Node* fast = plist;

	while( low && fast -> _pnext)
	{
		low = low->_pnext;
		fast = fast->_pnext;
		if(fast ->_pnext !=  NULL)
		{
			fast = fast->_pnext;
		}
		if(fast == low)
		{
			break;
		}
	}
	Node *meetnode = low;
 	Node* p = meetnode;
	int count = 1;
	
	while( p->_pnext != meetnode)
	{
		p = p->_pnext;
		count++;
	}

	Node *pNode1 = plist;
	for(int i = 0 ; i < count;i++)
	{
		pNode1 = pNode1 -> _pnext;
	}
	Node *pNode2 = plist;
	while(pNode1 != pNode2)
	{
		pNode1  = pNode1 -> _pnext;
		pNode2  = pNode2 -> _pnext;
	}
	return pNode1;
}


//测试用例

/*
	Node* pq =  Finde_Circle(&head1);

	if(pq)
	{
		cout<<"head1 list circle  addr ::"<<pq<<endl;
	}
	else
	{
		cout<<"head1 not list  circle addr ::"<<pq<<endl;
	}
	Node* pq1 =  Finde_Circle1(&head1);
	if(pq1)
	{
		cout<<"head1 list circle  addr ::"<<pq<<endl;
	}
	else
	{
		cout<<"head1 not list  circle addr ::"<<pq<<endl;
	}*/

(3)找出单链表倒数第K个节点

//找单链表倒数第k个节点 定义两个指针 一个先走k-1步,在两个指针同时走,
//当快指针到达尾部时,慢指针刚好指向倒数第K的节点
Node* Find_K_List(PClist plist,int k)
{
	if(plist == NULL || k == 0)
		return NULL;
	Node* pk = plist;
	Node* p0 = plist;

	for(int i = 0 ; i < k-1 ;++i)
	{
		if(pk ->_pnext != NULL)
		{
			pk = pk->_pnext;
		}
		else
		{
			cout<<"list xiaoyu k"<<endl;
			return NULL;
		}
	}

	while(pk ->_pnext != NULL)
	{
		pk = pk->_pnext;
		p0 = p0->_pnext;
	}
	return p0;
}


//测试用例
/*
	int k ;
	cin>>k;
	
		Node* pk = Find_K_List(&head1,k);
	    Show(&head1);
	   if(pk)
	   {
		  cout<<"倒数第k个节点"<<pk<<endl;
		  cout<<"倒数第k个节点"<<pk->_data<<endl;
	   } 
	   else
	   {
		   cout<<"未找到倒数第k个节点"<<endl;
	   }
*/

(4)找出单链表的中间节点

/*找单链表的中间节点  快指针一次走两步 慢指针一次走一步  
当快指针到达尾部时,如果链表长度为奇数,那么慢指针所指的就是中间节点
                    如果链表长度为偶数,那么慢指针和它的下一个都是中间节点
*/
Node* Find_Middle_List(PClist plist)
{
	if(plist == NULL)
		return NULL;
	Node* fast = plist;
	Node* low = plist;

	while(low && fast->_pnext)
	{
		low = low->_pnext;
		fast = fast->_pnext;
		if(fast->_pnext != NULL)
		{
			fast = fast->_pnext;
		}
	}
	return low;
}

//测试用例

/*
	Node *mid = Find_Middle_List(&head2);
	if(mid)
	{
		cout<<"this list mid data is "<<mid->_data<<endl;
	}else
	{
		cout<<"this list mid data is "<<mid->_data<<endl;
	}
	*/

(5)将链表的元素从尾到头打印

//如何从尾到头输出链表
void Print_Reserve(PClist plist)
{
	if(plist == NULL)
		return ;
	stack<Node*> st;

	for(Node* p = plist->_pnext;p != NULL ;p = p->_pnext)
	{
		st.push(p);
	}

	while(!st.empty())
	{
		cout<<(st.top())->_data<<" ";
		st.pop();
	}
	cout<<endl;
}

等待更新。。。。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值