<html>

<head><script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- MyFirstUnitAd -->
<ins class="adsbygoogle"
     style="display:inline-block;width:970px;height:250px"
     data-ad-client="ca-pub-5778386704669218"
     data-ad-slot="1503492166"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>

<meta http-equiv="Content-Language" content="zh-cn">
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Dependency</title>
</head>

<body>



<p align="left"><span lang="en-ca"><font size="6" color="#FF0000"><b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
Dependency(set)</b></font></span></p>

<div align="left">
  <pre><b><font color="#ff0000" size="5">A. <span lang="en-ca">Second</span> Edition</font></b></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>This is the second edition of my &quot;dependency&quot; and spend half day to implement a help class &quot;Set&quot; which will</b></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>be intensively used throughout this series.</b></span></pre>
</div>
<div align="left">
  <pre><b><font color="#ff0000" size="5"><span lang="en-ca">B</span>.<span lang="en-ca"><a name="problem"></a>The problem</span></font></b></pre>
</div>
<p ALIGN="LEFT"><span lang="en-ca"><font size="2"><b>&quot;Function dependency&quot; is a 
very important issue in database theory. And what's more, it is the essence of 
all.</b></font></span></p>
<p ALIGN="LEFT"><span lang="en-ca"><font size="2"><b>Because I think it is the 
key of knowledge: the world is described by relations and relations of 
relations.</b></font></span></p>
<div align="left">
  <p ALIGN="LEFT">　</div>
<div align="left">
  <b><font color="#ff0000" size="5"><span lang="en-ca"><a name="explain"></a>C</span>.<span lang="en-ca">The
  </span></font></b><span lang="en-ca"><font size="5" color="#FF0000"><b>idea of 
  program</b></font></span></div>
<div align="left">
  　</div>
<div align="left">
  <span lang="en-ca"><font size="2"><b>This is a rather old topic. There are 
  some topics I like to write programs over and over, such as DFS,DFA and </b></font></span></div>
<div align="left">
  　</div>
<div align="left">
  <span lang="en-ca"><font size="2"><b>Sets. Compared with the very, very first 
  approach more than a year ago, I now understand more about set theory.</b></font></span></div>
<div align="left">
  　</div>
<div align="left">
  <span lang="en-ca"><font size="2"><b>And I am using a rather simple way---bitset 
  which is in the standard template library(STL). </b></font></span></div>
<div align="left">
  　</div>
<div align="left">
  <pre><b><font color="#ff0000" size="5">D.<span lang="en-ca"><a name="Method"></a>The </span>major functions</font></b></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><font size="2"><b>There are few points to mention except for the &quot;forEachSubset&quot; function. I think I do it in a similar way like</b></font></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>&quot;strtok&quot;. Do you feel strange that I connect these two together? You first call &quot;forEachSubset&quot; once and then</b></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>repeatedly call &quot;eachSub&quot; function to get an output &quot;Set&quot; parameter which is a &quot;proper subset&quot; of calling object.</b></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>Please note that I ignore the calling set itself which is a trivial subset, but include the &quot;empty set&quot; at last.</b></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>(maybe I should remove the annoying empty set!?)</b></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>The implementation is simple: each existing bit has two choice: either in or not in. And I always do this kind of </b></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>algorithms like ancient Chinese &quot;calculus&quot;---or addition calculator.</b></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>The second feature is that I have become a fanatic about operator-overloading. I have used up the common operators</b></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>for overloading my &quot;set&quot; class.</b></span></pre>
</div>
<div align="left">
  <pre>　</pre>
</div>
<div align="left">
  <pre><b><font color="#ff0000" size="5"><span lang="en-ca">E</span>.</font></b><span lang="en-ca"><font size="5" color="#FF0000"><b>Further improvement</b></font></span></pre>
</div>
<div align="left">
  <pre>　</pre>
</div>
<div align="left">
  <pre><b><font color="#ff0000" size="5"><span lang="en-ca">F</span>.</font></b><span lang="en-ca"><font size="5" color="#FF0000"><b>File listing</b></font></span></pre>
</div>
<div align="left" style="width: 898; height: 86">
  <pre><font size="3"><b>1<span lang="en-ca">. rules.h </span></b></font></pre>
  <pre><span lang="en-ca"><font size="3"><b>2</b></font></span><font size="3"><b><span lang="en-ca">. rules.</span></b></font><span lang="en-ca"><font size="3"><b>cpp</b></font></span></pre>
  <pre><span lang="en-ca"><font size="3"><b>3</b></font></span><font size="3"><b><span lang="en-ca">. set.h</span></b></font></pre>
  <pre><span lang="en-ca"><font size="3"><b>4</b></font></span><font size="3"><b><span lang="en-ca">. set.</span></b></font><span lang="en-ca"><font size="3"><b>cpp</b></font></span></pre>
  <pre><span lang="en-ca"><font size="3"><b>5</b></font></span><font size="3"><b><span lang="en-ca">. main.cpp (main)</span></b></font></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><font size="3" color="#FF0000"><b>file name: set.h</b></font></span></pre>
</div>
<pre>#ifndef SET_H
#define SET_H

#include &lt;iostream&gt;
#include &lt;bitset&gt;

using namespace std;


const int MaxAttrNumber=20;

class Set
{
	//this is a long-pain for me, I have no other way to 
	//let compiler recognize this &quot;friend&quot; function outside declaration
	friend ostream&amp; operator&lt;&lt;(ostream&amp; out, const Set&amp; dummy)	
	{
		for (int i=0; i&lt;dummy.size; i++)
		{
			if (dummy.theSet.test(i))
			{
				out&lt;&lt;'1';
			}
			else
			{
				out&lt;&lt;'0';
			}
		}
		return out;
	}
private:
	bitset&lt;MaxAttrNumber&gt; theSet;
	int size;
	int current;
public:
	void setSize(const Set&amp; dummy);
	int next(int current);
	int first();	
	int count();
	Set intersection(const Set&amp; dummy);
	Set unionSet(const Set&amp; dummy);
	Set difference(const Set&amp; dummy);
	
	//I am crazy about operator overloading!!!:)
	Set operator-(const Set&amp; dummy);
	Set operator+(const Set&amp; dummy);
	Set operator*(const Set&amp; dummy);
	void operator=(const Set&amp; dummy);
	bool operator==(const Set&amp; dummy);
	bool operator!=(const Set&amp; dummy);
	bool operator&gt;(const Set&amp; dummy);
	bool operator&gt;=(const Set&amp; dummy);
	bool operator&lt;(const Set&amp; dummy);
	bool operator&lt;=(const Set&amp; dummy);
	void set(int pos);
	void forEachSubSet(Set&amp; dummy);//must be called before &quot;eachSub()&quot;
	bool eachSub(Set&amp; dummy);
	void set();
	void reset(int pos);
	void reset();
	bool test(int pos) const;
	bool isIn(const Set&amp; dummy);
	void setSize(int theSize) {size=theSize;}
	Set(int theSize=10);
};

#endif</pre>
  <pre><span lang="en-ca"><font size="3" color="#FF0000"><b>file name: set.cpp</b></font></span></pre>
<pre>#include &quot;Set.h&quot;

bool Set::isIn(const Set&amp; dummy)
{
	for (int i=0; i&lt;size; i++)
	{
		if (theSet.test(i))
		{
			if (!dummy.test(i))//here I use Set.test() instead of set.test()
			{
				return false;
			}
		}
	}
	return true;		
}

bool Set::test(int pos) const
{
	return (pos&lt;size&amp;&amp;theSet.test(pos));
}

//current=-1;//initialize to -1 to prepare for being called
int Set::next(int current)
{
	for (int i=current+1; i&lt;size; i++)//include situation current&gt;=size
	{
		if (theSet.test(i))
		{
			return i;
		}
	}
	return -1;//not found
}

bool Set::operator !=(const Set&amp; dummy)
{
	return !(this-&gt;operator ==(dummy));
}

bool Set::operator &lt;(const Set&amp; dummy)
{
	return (this-&gt;isIn(dummy)&amp;&amp;this-&gt;operator !=(dummy));
}

bool Set::operator &lt;=(const Set&amp; dummy)
{
	return isIn(dummy);
}

bool Set::operator &gt;(const Set&amp; dummy)
{
	return !(this-&gt;operator &lt;=(dummy));
}

bool Set::operator &gt;=(const Set&amp; dummy)
{
	return !(this-&gt;operator &lt;(dummy));
}

bool Set::operator ==(const Set&amp; dummy)
{
	for (int i=0; i&lt;(size&gt;dummy.size?size:dummy.size); i++)
	{
		if (test(i)^dummy.test(i))
		{
			return false;
		}
	}
	return true;
}

void Set::setSize(const Set&amp; dummy)
{
	size=dummy.size;
}

void Set::operator =(const Set&amp; dummy)
{
	size=dummy.size;
	for (int i=0; i&lt;size; i++)
	{
		if (dummy.test(i))
		{
			theSet.set(i);
		}
		else
		{
			theSet.reset(i);
		}
	}
}


Set::Set(int theSize)
{
	size=theSize;
	reset();
}

void Set::reset()
{
	for (int i=0; i&lt;size; i++)
	{
		theSet.reset(i);
	}
}

void Set::reset(int pos)
{
	if (pos&lt;size)
	{
		theSet.reset(pos);
	}
}

void Set::set()
{
	theSet.set();
}

void Set::set(int pos)
{
	theSet.set(pos);
}
	
void Set::forEachSubSet(Set&amp; dummy)
{
	dummy=*this;
}


bool Set::eachSub(Set&amp; dummy)
{
	int index=first();//starting from very first

	while (index!=-1)//not exceeding boundery
	{
		if (dummy.test(index))
		{
			dummy.reset(index);
			return true;
		}
		else
		{
			dummy.set(index);
			index=next(index);
		}
	}
	return false;
}

int Set::first()
{
	return next(-1);
}

int Set::count()
{
	return theSet.count();
}

Set Set::unionSet(const Set&amp; dummy)
{
	Set result;
	result.size=size&gt;dummy.size?size:dummy.size;
	for (int i=0; i&lt;result.size; i++)
	{
		if (test(i)||dummy.test(i))
		{
			result.set(i);
		}
	}
	return result;//this is a temparory object;
}

Set Set::difference(const Set&amp; dummy)
{
	Set result;
	result.size=size&gt;dummy.size?size:dummy.size;
	for (int i=0; i&lt;result.size; i++)
	{
		if (test(i)&amp;&amp;!dummy.test(i))
		{
			result.set(i);
		}
	}
	return result;
}

Set Set::operator +(const Set&amp; dummy)
{
	return unionSet(dummy);
}

Set Set::operator -(const Set&amp; dummy)
{
	return difference(dummy);
}

Set Set::intersection(const Set&amp; dummy)
{
	Set result;
	result.size=size&lt;dummy.size?size:dummy.size;
	for (int i=0; i&lt;result.size; i++)
	{
		if (test(i)&amp;&amp;dummy.test(i))
		{
			result.set(i);
		}
	}
	return result;
}

Set Set::operator *(const Set&amp; dummy)
{
	return intersection(dummy);
}

</pre>
<pre>
</pre>
  <pre><span lang="en-ca"><font size="3" color="#FF0000"><b>file name: rules.h </b></font></span></pre>
<pre>#include &lt;iostream&gt;
#include &lt;bitset&gt;
#include &quot;set.h&quot;

using namespace std;

//make it simple, the first line must list all variables or attributes
//&quot;relation&quot;(A,B,C...)
const int MaxNameLength=5;
const int MaxRuleNumber=100;




class Rule
{
	friend class Rules;
private:
	Set lhs;
	Set rhs;	
public:	
	Rule();
	bool test(int pos, bool isLeft);
	void lhsSet(int pos);
	void rhsSet(int pos);
	void setSize(int theSize);
	void set(int pos, bool isLeft);
	void setRule(const Set&amp; left, const Set&amp; right);
	void operator=(const Rule&amp; dummy);
};

class Rules
{
private:
	char attributes[MaxAttrNumber][MaxNameLength+1];
	char relationName[MaxNameLength+1];
	int attrCount;
	int attrFound[MaxAttrNumber];
	int numberFound;
	int searchByChar(char ch, int step);
	void ruleReading(FILE* stream);
	Rule rules[MaxRuleNumber];
	int ruleNumber;
	void displayRule(int index);
	void split();
	void addRule(const Set&amp; left, const Set&amp; right);
	int extractNames(FILE* stream, char* delimeters, char endChar='\n');
public:
	void addRule(const Rule&amp; dummy);
	void readFile(const char* fileName);
	void display();
	Rules();
};
</pre>
<pre>　</pre>

<pre><span lang="en-ca"><font size="3" color="#FF0000"><b>file name: rules.cpp </b></font></span></pre>

<pre>#include &quot;Rules.h&quot;


void Rules::display()
{
	cout&lt;&lt;&quot;\nnow display\n&quot;;
	cout&lt;&lt;relationName&lt;&lt;&quot;(&quot;;
	for (int i=0; i&lt;attrCount; i++)
	{
		cout&lt;&lt;attributes[i];
		if (i!=attrCount-1)
		{
			cout&lt;&lt;&quot;,&quot;;
		}
		else
		{
			cout&lt;&lt;&quot;);\n&quot;;
		}
	}
	for (i=0; i&lt;ruleNumber; i++)
	{
		displayRule(i);
	}
}


bool Rule::test(int pos, bool isLeft)
{
	if (isLeft)
	{
		return lhs.test(pos);
	}
	else
	{
		return rhs.test(pos);
	}
}


void Rules::displayRule(int index)
{
	for (int i=0; i&lt;attrCount; i++)
	{
		if (rules[index].test(i, true))
		{
			cout&lt;&lt;attributes[i];
		}
	}
	cout&lt;&lt;&quot; -&gt; &quot;;
	for (i=0; i&lt;attrCount; i++)
	{
		if (rules[index].test(i, false))
		{
			cout&lt;&lt;attributes[i];
		}
	}
	cout&lt;&lt;&quot;;\n&quot;;
}


void Rule::set(int pos, bool isLeft)
{
	if (isLeft)
	{
		lhsSet(pos);
	}
	else
	{
		rhsSet(pos);
	}
}

void Rule::rhsSet(int pos)
{
	rhs.set(pos);
}

void Rule::lhsSet(int pos)
{
	lhs.set(pos);
}

Rule::Rule()
{
	lhs.reset();
	rhs.reset();
	
}


void Rules::readFile(const char* fileName)
{
	FILE* stream;
	stream=fopen(fileName, &quot;r&quot;);
	attrCount=extractNames(stream, &quot;=,()&quot;, ';');//ignore the first relation name
	ruleReading(stream);

}

void Rules::ruleReading(FILE* stream)
{
	char ch;
	int step=0;
	ruleNumber=0;//initialize
	bool isLeft=true;
	rules[ruleNumber].setSize(attrCount);//do twice!!
	while (!feof(stream))
	{		
		ch=fgetc(stream);
		if (ch==';'||ch==',')
		{
			ruleNumber++;
			rules[ruleNumber].setSize(attrCount);//do twice!!
			isLeft=true;
		}
		else
		{
			if (ch=='-'||ch=='&gt;')
			{
				isLeft=false;
			}
			else
			{
				if (isalpha(ch))
				{
					searchByChar(ch, step);
					if (numberFound!=1)
					{
						if (step&lt;MaxNameLength)
						{
							step++;
						}
						else
						{
							cout&lt;&lt;&quot;illegal attribute stated!\n&quot;;
							exit(1);
						}
					}
					else
					{
						step=0;
						
						rules[ruleNumber].set(attrFound[0], isLeft);
					}
				}
			}
		}
	}
}

void Rule::setSize(int theSize)
{
	lhs.setSize(theSize);
	rhs.setSize(theSize);
}
	

int Rules::searchByChar(char ch, int step)
{
	if (step==0)//this is first time, and all attributes are searched
	{
		numberFound=0;
		for (int i=0; i&lt;attrCount; i++)//
		{
			if (ch==attributes[i][step])
			{
				attrFound[numberFound]=i;
				numberFound++;
			}
		}
	}
	else
	{
		int number=0;//new 'attrFound' re-counting
		for (int i=0; i&lt;numberFound; i++)
		{
			if (ch==attributes[attrFound[i]][step])
			{
				attrFound[number]=i;
				number++;
			}
		}
		numberFound=number;
	}
	return numberFound;
}


int findChar(char ch, char* str)
{
	int index=0;
	while (str[index]!='\0')
	{
		if (str[index]==ch)
		{
			return index;
		}
		index++;
	}
	return -1;
}

//extract names from a line delimetered by various chars, like ',','(',')'....
int Rules::extractNames(FILE* stream, char* delimeters, char endChar)
{
	int findChar(char ch, char* str);
	char ch;
	int nameIndex=0;
	char buffer[MaxNameLength+1];
	char* ptr=buffer;

	while (!feof(stream))
	{
		ch=getc(stream);
		if (ch==endChar)
		{
			if (ptr!=buffer)
			{
				*ptr='\0';
				strcpy(attributes[nameIndex], buffer);
			}
			break;
		}

		if (findChar(ch, delimeters)&gt;0)//deli reached
		{
			//skip the consecutive deli
			if (ptr!=buffer)
			{
				*ptr='\0';	
				if (ch=='(')//the very first one
				{
					strcpy(relationName, buffer);
				}
				else
				{
					strcpy(attributes[nameIndex], buffer);
					nameIndex++;
				}
				ptr=buffer;//restart
			}
		}
		else
		{
			*ptr=ch;
			ptr++;
		}
	}
	return nameIndex;
}		

Rules::Rules()
{
	numberFound=attrCount=0;
}
	
void Rule::operator =(const Rule&amp; dummy)
{
	lhs=dummy.lhs;
	rhs=dummy.rhs;
}

void Rules::addRule(const Rule&amp; dummy)
{
	rules[ruleNumber++]=dummy;
}

void Rules::addRule(const Set&amp; left, const Set&amp; right)
{
	rules[ruleNumber++].setRule(left, right);
}

void Rule::setRule(const Set&amp; left, const Set&amp; right)
{
	lhs=left;
	rhs=right;
}

void Rules::split()
{
	int index;
	for (int i=0; i&lt;ruleNumber; i++)
	{
		if (rules[i].rhs.count()&gt;1)
		{			
			index=rules[i].rhs.first();
			index=rules[i].rhs.next(index);//starting from second one
			while (index!=-1)
			{
				Set right;				
				right.setSize(rules[i].rhs);
				right.set(index);
				rules[i].rhs.reset(index);//remove from old rule
				addRule(rules[i].lhs, right);
				index=rules[i].rhs.next(index);
			}
		}
	}
}

</pre>
<pre>　</pre>

<pre><span lang="en-ca"><font size="3" color="#FF0000"><b>file name: main.cpp (main)</b></font></span></pre>

<pre>　</pre>

<pre>#include &quot;Rules.h&quot;
#include &quot;set.h&quot;

int main()
{
	Rules R;
	R.readFile(&quot;d:\\rules.txt&quot;);
	R.display();

	return 0;
}</pre>
<pre>　</pre>

<pre></pre>

<pre></pre>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;                                   
&nbsp;&nbsp;&nbsp; <a href="game24.htm">                  







                       <img src="picture/back.gif" style="border: medium none" alt="back.gif (341 bytes)" width="32" height="35"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<a href="index.htm">
<img src="picture/up.gif" style="border: medium none" alt="up.gif (335 bytes)" width="35" height="32"></a>       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;                         
<img src="picture/next.gif" style="border: medium none" alt="next.gif (337 bytes)" width="32" height="35">          


</p>

</body>

</html>