示例代码: http://download.csdn.net/detail/ayang1986/9586701
// HorzListBox.h : 头文件
//
/*****************************************************************
作者:ayang1986
版本:v1.0 (2016.7.26)
说明:适用于MFC,CListBox子类, 自动水平滚动条
*****************************************************************/
#pragma once
// class SBTree
class SBTNode
{
public:
int key;
unsigned int account;
private:
friend class SBTree;
SBTNode *p, *left, *right;
unsigned int Size;
public:
SBTNode(int _key)
{
key = _key;
Size = 1;
account = 1;
left = NULL;
right = NULL;
};
};
class SBTree
{
private:
void LeftRotate(SBTNode* x);//左旋函数
void RightRotate(SBTNode* x);//右旋函数
SBTNode* DeleteSuccessor(SBTNode* x);
void Empty(SBTNode* &x);//清空指定子树
bool Insert(int k, SBTNode* &z);//插入函数
SBTNode* Search(SBTNode* x, int k); //中序检索函数
SBTNode *Root, *Nil;//根节点、哨兵节点
unsigned int NUM;
public:
SBTree()
{
Nil = new SBTNode(0);
Nil->Size = 0;
Nil->account = 0;
Nil->left = Nil;
Nil->right = Nil;
NUM = 0;
Root = Nil;
};//构造函数
~SBTree()
{
delete Nil;
Empty();
};//析构函数
SBTNode* Insert(int k);//插入函数
void Delete(int k);//删除函数,若找不到所输入元素则返回
void Maintain(SBTNode* x, bool IsRight);//主调整函数
SBTNode* Search(int k);//中序检索函数
SBTNode* Successor(SBTNode* x);//后继
SBTNode* Predecessor(SBTNode* x);//前趋
SBTNode* Minimum(SBTNode* x = NULL);//最小值
SBTNode* Maximum(SBTNode* x = NULL);//最大值
void Print(SBTNode* &x);// 升序打印指定子树
void Print();// 升序打印整棵树
void Empty();//清空整棵树
unsigned int Count(); //整棵树元素个数
};
// CHorzListBox
class CHorzListBox : public CListBox
{
DECLARE_DYNAMIC(CHorzListBox)
public:
CHorzListBox();
virtual ~CHorzListBox();
protected:
DECLARE_MESSAGE_MAP()
public:
int AddString(LPCTSTR lpszItem);
int DeleteString(UINT nIndex);
int InsertString(int nIndex, LPCTSTR lpszItem);
void ResetContent();
int Dir(UINT attr, LPCTSTR lpszWildCard); // 该函数没有设置宽度接口, 屏蔽该函数
void Print();
private:
//BOOL IsVertVisible(); // 垂直滚动条是否可见
int GetHorzWidth(int nIndex); // 获取字串宽度
void UpdateHorzScrollBar(int nWidth, BOOL blAdd); // 更新水平滚动条
SBTree m_treeWidth;
};
// HorzListBox.cpp : 实现文件
//
#include "stdafx.h"
#include "MFCListBox.h"
#include "HorzListBox.h"
// SBTree
void SBTree::LeftRotate(SBTNode* x)
{
SBTNode*y = x->right;
x->right = y->left;
if (y->left != Nil)
{
y->left->p = x;
};
y->p = x->p;
if (x->p == Nil)
{
Root = y;
}
else{
if (x == x->p->left)
{
x->p->left = y;
}
else{
x->p->right = y;
};
};
x->p = y;
y->left = x;
y->Size = x->Size;
x->Size = x->left->Size + x->right->Size + 1;//Size的维护
}
void SBTree::RightRotate(SBTNode* x)
{
SBTNode*y = x->left;
x->left = y->right;
if (y->right != Nil)
{
y->right->p = x;
};
y->p = x->p;
if (x->p == Nil)
{
Root = y;
}
else{
if (x == x->p->right)
{
x->p->right = y;
}
else{
x->p->left = y;
};
};
x->p = y;
y->right = x;
y->Size = x->Size;
x->Size = x->left->Size + x->right->Size + 1;//Size的维护
}
SBTNode* SBTree::Insert(int k)
{
SBTNode*x = Root, *y = Nil;
while (x != Nil)
{
if (k == x->key)
{
x->account++;
NUM++;
y = x;
x = x->p;
while (x != Nil)
{
x->Size--;
x = x->p;
};
return y;
};//若有相同元素则计数加1,恢复先祖的Size
x->Size++;
y = x;
if (k < x->key)
{
x = x->left;
}
else{
x = x->right;
};
};
SBTNode* z = new SBTNode(k);
z->p = y;
if (y == Nil)
{
Root = z;
}
else{
if (k < y->key)
{
y->left = z;
}
else{
y->right = z;
};
};
z->left = Nil;
z->right = Nil;
while (y != Nil)
{
Maintain(y, k >= y->key);
y = y->p;
};
return z;
}
void SBTree::Delete(int k)
{
SBTNode*z = Root, *w = Nil;
while (k != z->key && z != Nil)
{
z->Size--;
w = z;
if (k < z->key)
{
z = z->left;
}
else{
z = z->right;
};
};
if (z == Nil)
{
while (w != Nil)
{
w->Size++;
w = w->p;
};//若没找到,则恢复先祖的Size
}
else{
if (z->account > 1)
{
z->account--;
NUM--;
while (w != Nil)
{
w->Size++;
w = w->p;
};
return;
};//若计数大于1,则计数减1,并恢复先祖的Size
SBTNode*y, *x;
if (z->left == Nil || z->right == Nil)
{
y = z;
}
else{
y = DeleteSuccessor(z);
};
if (y->left != Nil)
{
x = y->left;
}
else{
x = y->right;
};
x->p = y->p;
if (y->p == Nil)
{
Root = x;
}
else{
if (y == y->p->left)
{
y->p->left = x;
}
else{
y->p->right = x;
};
};
if (y != z)
{
z->key = y->key;
z->account = y->account;
};
delete y;
};
}
//删除中使用的后继函数,一边搜索,一边减小Size
SBTNode* SBTree::DeleteSuccessor(SBTNode* x)
{
x->Size--;
x = x->right;
while (x->left != Nil)
{
x->Size--;
x = x->left;
};
return x;
}
void SBTree::Maintain(SBTNode* x, bool IsRight)
{
if (IsRight)
{
if (x->right->right->Size > x->left->Size)
{
LeftRotate(x);
}
else{
if (x->right->left->Size > x->left->Size)
{
RightRotate(x->right);
LeftRotate(x);
}
else{
return;
};
};
}
else{
if (x->left->left->Size > x->right->Size)
{
RightRotate(x);
}
else{
if (x->left->right->Size > x->right->Size)
{
LeftRotate(x->left);
RightRotate(x);
}
else{
return;
};
};
};
Maintain(x->p->left, false);
Maintain(x->p->right, true);
Maintain(x->p, true);
Maintain(x->p, false);
}
SBTNode* SBTree::Successor(SBTNode* x)
{
if (x->right != Nil)
return Minimum(x->right);
SBTNode*y = x->p;
while (y != Nil && x == y->right)
{
x = y;
y = y->p;
};
return y;
}
SBTNode* SBTree::Predecessor(SBTNode* x)
{
if (x->right != Nil)
return Minimum(x->right);
SBTNode*y = x->p;
while (y != Nil && x == y->right)
{
x = y;
y = y->p;
};
return y;
}
SBTNode* SBTree::Minimum(SBTNode* x)
{
if (x == NULL) x = Root;
while (x->left != Nil)
{
x = x->left;
};
return x;
}
SBTNode* SBTree::Maximum(SBTNode* x)
{
if (x == NULL) x = Root;
while (x->right != Nil)
{
x = x->right;
};
return x;
}
SBTNode* SBTree::Search(int k)
{
return Search(Root, k);
}
SBTNode* SBTree::Search(SBTNode* x, int k)
{
while (x != Nil && k != x->key)
{
if (k < x->key)
{
x = x->left;
}
else{
x = x->right;
};
};
return x;
}
void SBTree::Print(SBTNode* &x)
{
if (x->left != Nil)
Print(x->left);
TRACE("%d ( %d )\n", x->key, x->account);
if (x->right != Nil)
Print(x->right);
}
void SBTree::Print()
{
if (Root == Nil)
{
TRACE("Empty tree!\n");
return;
};
Print(Root);
}
void SBTree::Empty()
{
if (Root != Nil)
{
Empty(Root);
Root = Nil;
NUM = 0;
};
}
void SBTree::Empty(SBTNode* &x)
{
if (x->left != Nil)
Empty(x->left);
if (x->right != Nil)
Empty(x->right);
delete x;
}
unsigned int SBTree::Count()
{
return (Root->Size + NUM);
}
// CHorzListBox
IMPLEMENT_DYNAMIC(CHorzListBox, CListBox)
CHorzListBox::CHorzListBox()
{
}
CHorzListBox::~CHorzListBox()
{
}
BEGIN_MESSAGE_MAP(CHorzListBox, CListBox)
END_MESSAGE_MAP()
// CHorzListBox 消息处理程序
int CHorzListBox::AddString(LPCTSTR lpszItem)
{
int nIndex = CListBox::AddString(lpszItem);
if (nIndex != LB_ERR)
{
int nWidth = GetHorzWidth(nIndex);
UpdateHorzScrollBar(nWidth, TRUE);
}
return nIndex;
}
int CHorzListBox::DeleteString(UINT nIndex)
{
int nWidth = GetHorzWidth(nIndex);
int nRtIndex = CListBox::DeleteString(nIndex);
if (nRtIndex != LB_ERR)
{
UpdateHorzScrollBar(nWidth, FALSE);
}
return nRtIndex;
}
int CHorzListBox::InsertString(int nIndex, LPCTSTR lpszItem)
{
int nRtIndex = CListBox::InsertString(nIndex, lpszItem);
if ((nRtIndex != LB_ERR) && (nRtIndex != LB_ERRSPACE))
{
int nWidth = GetHorzWidth(nRtIndex);
UpdateHorzScrollBar(nWidth, TRUE);
}
return nRtIndex;
}
void CHorzListBox::ResetContent()
{
CListBox::ResetContent();
SetHorizontalExtent(0);
m_treeWidth.Empty();
}
int CHorzListBox::Dir(UINT attr, LPCTSTR lpszWildCard)
{
ASSERT(FALSE);
return LB_ERR;
}
//=======================================================================
// 垂直滚动条是否可见
//BOOL CHorzListBox::IsVertVisible()
//{
// SCROLLBARINFO scrollbarInfo = { 0 };
// scrollbarInfo.cbSize = sizeof(SCROLLBARINFO);
// GetScrollBarInfo(OBJID_VSCROLL, &scrollbarInfo);
// if (scrollbarInfo.rgstate[0] & STATE_SYSTEM_INVISIBLE)
// {
// return FALSE;
// }
// else
// {
// return TRUE;
// }
//}
//=======================================================================
// 获取字串宽度
int CHorzListBox::GetHorzWidth(int nIndex)
{
CString str;
CSize sz;
TEXTMETRIC tm;
CDC* pDC = GetDC();
CFont* pFont = GetFont();
CFont* pOldFont = pDC->SelectObject(pFont); // Select the listbox font, save the old font
pDC->GetTextMetrics(&tm); // Get the text metrics for avg char width
GetText(nIndex, str);
sz = pDC->GetTextExtent(str);
sz.cx += tm.tmAveCharWidth; // Add the avg width to prevent clipping
pDC->SelectObject(pOldFont); // Select the old font back into the DC
ReleaseDC(pDC);
return sz.cx;
}
//=======================================================================
// 更新水平滚动条
// blAdd: TRUE 增加, FALSE 删除
void CHorzListBox::UpdateHorzScrollBar(int nWidth, BOOL blAdd)
{
if (blAdd)
{
int nMax = m_treeWidth.Maximum()->key;
m_treeWidth.Insert(nWidth);
if (nMax < nWidth)
{
SetHorizontalExtent(nWidth);
}
}
else
{
m_treeWidth.Delete(nWidth);
int nMax = m_treeWidth.Maximum()->key;
if (nMax < nWidth)
{
SetHorizontalExtent(nMax);
}
}
}
void CHorzListBox::Print()
{
m_treeWidth.Print();
}