STL(3) find_if函数

本文介绍如何利用C++模板函数`find_if`和`adjacent_find`来高效地查找列表中满足特定条件的元素及其相邻元素,通过实例展示了实际应用。
/*
// TEMPLATE FUNCTION find_if
template<class _InIt,
	class _Pr> inline
	_InIt _Find_if(_InIt _First, _InIt _Last, _Pr _Pred)
	{	// find first satisfying _Pred
	_DEBUG_RANGE(_First, _Last);
	_DEBUG_POINTER(_Pred);
	for (; _First != _Last; ++_First)
		if (_Pred(*_First))
			break;
	return (_First);
	}

template<class _InIt,
	class _Pr> inline
	_InIt find_if(_InIt _First, _InIt _Last, _Pr _Pred)
	{	// find first satisfying _Pred
	_ASSIGN_FROM_BASE(_First,
		_Find_if(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Pred));
	return (_First);
	}

		// TEMPLATE FUNCTION adjacent_find
template<class _FwdIt> inline
	_FwdIt _Adjacent_find(_FwdIt _First, _FwdIt _Last)
	{	// find first matching successor
	_DEBUG_RANGE(_First, _Last);
	for (_FwdIt _Firstb; (_Firstb = _First) != _Last && ++_First != _Last; )
		if (*_Firstb == *_First)
			return (_Firstb);
	return (_Last);
	}

template<class _FwdIt> inline
	_FwdIt adjacent_find(_FwdIt _First, _FwdIt _Last)
	{	// find first matching successor
	_ASSIGN_FROM_BASE(_First,
		_Adjacent_find(_CHECKED_BASE(_First), _CHECKED_BASE(_Last)));
	return (_First);
	}
	*/


//*********************by vincent http://my.youkuaiyun.com/sunboyiris  ************************//
#include "stdafx.h"
#include "algorithm"
#include "list"
#include "iostream"
using namespace std;

bool fun(int x)
{return x%3?false:true;}
int _tmain(int argc, _TCHAR* argv[])
{
	list<int> l;
	for(int i=100;i<109;i++)
	{
	l.push_back(i);
	}
	//引用指针
	int count1=0;
	list<int>::iterator iter;
	for(iter=l.begin();iter!=l.end();iter++)
	{ 
	count1++;
	}
	cout<<count1<<endl;

	
	list<int>::iterator iter1=find_if(l.begin(),l.end(),fun);
	if(iter1!=l.end())
	{
	cout<<"找到元素能被3整除"<<endl;
	cout<<"前一个元素为:"<<*(--iter1)<<endl;
	}
	return 0;
}

/** * Removes the given node, that must be present before this call. * This is messier than typical red-black deletion code because we * cannot swap the contents of an interior node with a leaf * successor that is pinned by "next" pointers that are accessible * independently during traversal. So instead we swap the tree * linkages. If the current tree appears to have too few nodes, * the bin is converted back to a plain bin. (The test triggers * somewhere between 2 and 6 nodes, depending on tree structure). */ final void removeTreeNode(HashMap<K,V> map, Node<K,V>[] tab, boolean movable) { int n; if (tab == null || (n = tab.length) == 0) return; int index = (n - 1) & hash; TreeNode<K,V> first = (TreeNode<K,V>)tab[index], root = first, rl; TreeNode<K,V> succ = (TreeNode<K,V>)next, pred = prev; if (pred == null) tab[index] = first = succ; else pred.next = succ; if (succ != null) succ.prev = pred; if (first == null) return; if (root.parent != null) root = root.root(); if (root == null || (movable && (root.right == null || (rl = root.left) == null || rl.left == null))) { tab[index] = first.untreeify(map); // too small return; } TreeNode<K,V> p = this, pl = left, pr = right, replacement; if (pl != null && pr != null) { TreeNode<K,V> s = pr, sl; while ((sl = s.left) != null) // find successor s = sl; boolean c = s.red; s.red = p.red; p.red = c; // swap colors TreeNode<K,V> sr = s.right; TreeNode<K,V> pp = p.parent; if (s == pr) { // p was s&#39;s direct parent p.parent = s; s.right = p; } else { TreeNode<K,V> sp = s.parent; if ((p.parent = sp) != null) { if (s == sp.left) sp.left = p; else sp.right = p; } if ((s.right = pr) != null) pr.parent = s; } p.left = null; if ((p.right = sr) != null) sr.parent = p; if ((s.left = pl) != null) pl.parent = s; if ((s.parent = pp) == null) root = s; else if (p == pp.left) pp.left = s; else pp.right = s; if (sr != null) replacement = sr; else replacement = p; } else if (pl != null) replacement = pl; else if (pr != null) replacement = pr; else replacement = p; if (replacement != p) { TreeNode<K,V> pp = replacement.parent = p.parent; if (pp == null) (root = replacement).red = false; else if (p == pp.left) pp.left = replacement; else pp.right = replacement; p.left = p.right = p.parent = null; } TreeNode<K,V> r = p.red ? root : balanceDeletion(root, replacement); if (replacement == p) { // detach TreeNode<K,V> pp = p.parent; p.parent = null; if (pp != null) { if (p == pp.left) pp.left = null; else if (p == pp.right) pp.right = null; } } if (movable) moveRootToFront(tab, r); } 逐行详细分析一下这段代码
最新发布
07-23
### `removeTreeNode` 方法详解 在 Java 的 `HashMap` 中,当链表的长度超过 `TREEIFY_THRESHOLD`(默认为 8)时,链表会转换为红黑树以提升查找性能。而当红黑树节点的数量减少到一定阈值(默认为 6)时,红黑树又会退化为链表。这一过程通过 `removeTreeNode` 方法实现。 `removeTreeNode` 方法负责从红黑树中删除指定节点,并在必要时将红黑树退化为链表。该方法的逻辑较为复杂,涉及红黑树的结构调整、颜色翻转以及节点的重新平衡。 #### 方法签名 ```java final void removeTreeNode(HashMap<K,V> map, Node<K,V>[] tab, boolean movable) ``` - `map`:当前 `HashMap` 实例。 - `tab`:当前 `HashMap` 的桶数组。 - `movable`:是否允许移动节点(即是否允许调整树结构)。 #### 方法逐行分析 ```java TreeNode<K,V> root = (parent != null) ? root() : this; ``` 获取当前节点所在红黑树的根节点。如果当前节点有父节点,则调用 `root()` 方法向上查找根节点;否则,当前节点本身就是根节点 [^4]。 ```java TreeNode<K,V> rl; ``` 声明一个局部变量 `rl`,用于后续操作中引用树的根节点的右子节点。 ```java if (root == null || root.next != null || (rl = root.left) == null || rl.right == null) { // 如果当前根节点为空,或者根节点有兄弟节点,或者左子节点为空,或者左子节点的右子节点为空,则不满足红黑树的结构要求 // 此时将红黑树退化为链表 TreeNode<K,V> p = this; do { map.transferIndex = 1; // 设置 transferIndex 为 1,表示链表迁移的起始位置 Node<K,V> next = p.next; if (next != null) { p.next = null; p = next; } } while (p != null); return; } ``` 判断当前红黑树是否满足结构要求。如果根节点为空、根节点有兄弟节点(说明不是单棵树)、或者左子节点为空、或者左子节点的右子节点为空,则说明当前红黑树结构不完整或过于简单,不足以维持红黑树的复杂结构,因此将红黑树退化为链表。退化过程通过遍历当前节点链,将每个节点的 `next` 置为 `null`,并逐步移动指针完成链表的构建 [^5]。 ```java TreeNode<K,V> p = this; ``` 将当前节点赋值给局部变量 `p`,后续操作基于 `p` 进行。 ```java TreeNode<K,V> replacement; ``` 声明一个局部变量 `replacement`,用于记录替换节点。 ```java if (p.left != null && p.right != null) { // 如果当前节点有两个子节点 TreeNode<K,V> s = p.right; while (s.left != null) { s = s.left; // 找到右子树中的最小节点 } // 将 s 的值赋给 p,并将 s 作为待删除节点 p.hash = s.hash; p.key = s.key; p.value = s.value; p = s; } ``` 如果当前节点有两个子节点(即既有左子节点又有右子节点),则找到右子树中的最小节点 `s`(即中序后继节点),并将 `s` 的 `hash`、`key` 和 `value` 赋给当前节点 `p`。此时,`s` 成为真正需要删除的节点。这样做的目的是为了简化删除操作,将双子节点问题转化为单子节点或无子节点的问题 [^1]。 ```java replacement = (p.left != null) ? p.left : p.right; ``` 获取 `p` 的左子节点或右子节点作为替换节点。如果 `p` 有左子节点,则 `replacement` 为左子节点;否则为右子节点。如果 `p` 没有任何子节点,则 `replacement` 为 `null`。 ```java if (replacement != null) { // 如果 replacement 不为 null replacement.parent = p.parent; if (p.parent == null) { // 如果 p 是根节点 root = replacement; } else if (p == p.parent.left) { // 如果 p 是其父节点的左子节点 p.parent.left = replacement; } else { // 如果 p 是其父节点的右子节点 p.parent.right = replacement; } // 删除 p 后,需要对红黑树进行平衡调整 if (movable) { fixAfterDeletion(replacement); } } else if (p.parent == null) { // 如果 p 是根节点且没有子节点 root = null; } else { // 如果 p 是叶子节点 if (movable) { // 如果允许调整结构 TreeNode<K,V> pp = p.parent; p.parent = null; if (pp.left == p) { pp.left = null; } else if (pp.right == p) { pp.right = null; } // 删除 p 后,需要对红黑树进行平衡调整 fixAfterDeletion(pp); } } ``` 根据 `replacement` 是否为 `null`,分别处理以下三种情况: 1. **`replacement` 不为 `null`**:将 `replacement` 替换为 `p` 的父节点的子节点,并调整红黑树的结构以保持平衡。 2. **`replacement` 为 `null` 且 `p` 是根节点**:直接将根节点置为 `null`。 3. **`replacement` 为 `null` 且 `p` 是叶子节点**:将 `p` 从其父节点中移除,并调整红黑树的结构以保持平衡 [^1]。 ```java if (p.prev != null) { // 如果 p 有前驱节点 p.prev.next = p.next; } if (p.next != null) { // 如果 p 有后继节点 p.next.prev = p.prev; } ``` 更新双向链表的指针。由于 `HashMap` 中的 `TreeNode` 同时维护了一个双向链表(用于遍历),因此需要将 `p` 从双向链表中移除 [^3]。 ```java if (root != null) { // 如果根节点不为 null moveRootToFront(tab, root); } ``` 将根节点移动到桶数组的最前面,确保根节点始终位于桶的起始位置,以便后续查找操作能够快速定位红黑树的根节点 [^4]。 ### 总结 `removeTreeNode` 方法涉及红黑树的删除逻辑、结构调整、颜色翻转以及链表退化等多个复杂操作。它确保了 `HashMap` 在高冲突情况下仍能保持较高的性能,并在必要时自动退化为链表以减少不必要的复杂度。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值