注册 登录
编程论坛 C++教室

C++区联合程序开发

myajax95 发布于 2006-09-24 01:37, 3856 次点击

C++是一种十分优秀的语言,它的好处我就不在这里多说了。为了帮助大家更好的应用这们语言。C++区正在尝试联合编写程序。
如果大家有志于将来通过C++找工作,或者已经在工作中应用着这种语言,希望有更多提高。不妨参加我们的活动。一般从参加工作开始,每个人都要经过这样一个过程。先学习公司已有的程序,作最简单的修补。随着知识的积累可以改一些更重要的程序,甚至可以独立写一个feature。水平进一步提高,可以主持开发一个component。最后水平达到公司最高的时候可以成为公司的框架师。负责维护或重新开发整套系统。不是每一个人都能走到这一步。不过在这里,我们希望给大家一个互相学习的机会。给在不同阶段的网友一个在自己基础上进一步提高的机会。

我们这个活动几个月前开始搞,暑假阶段停了几个月。现在希望能继续坚持下去。编程环境选的是VC6.0
由于大家的起点可能不同,我们尽量从简单的开始。最先开始的是一个算法演示的小程序。这个程序还在不断的改进中。独立实现一个算法需要不少VC++/MFC的知识。大家如果觉得这部份知识不够的话可以在VC++区学习,或者先写只用C++的算法实现部份。就像我前面说的,从修修补补开始,逐渐能够实现一个单独的算法,在到能够设计更复杂的框架。

这里编程由于没有时间限制,希望大家尽量把自己的程序写到自己认为最满意的程度。先学的什么知识技巧尽量用上。这也是提高自己水平的必经之路。

希望大家想出更多更好的题目。同时欢迎各高手指点,或帮助设计框架。如果题目不在这个帖子的第一页,我们会把题目的链接放在这里。

[此贴子已经被作者于2006-9-24 1:48:29编辑过]

37 回复
#2
myajax952006-09-24 01:51
现在正在作的是一个算法演示的程序。源程序如下(更新:09/23)
只有本站会员才能查看附件,请 登录



[此贴子已经被作者于2006-9-24 1:58:17编辑过]

#3
wfpb2006-09-25 13:09

#include \"stdafx.h\"
#include <iostream>
#include <ctime>
#include <fstream>
using namespace std;
class Timer
{     clock_t start_time;
public:
    Timer(){start_time=clock();}
    void elaspe()
        /*计算时间*/
    {
        clock_t end_time=clock();
        cout<<\"It takes \"<<(double)(end_time-start_time)/(double)CLK_TCK<<\"seconds\n\";
    }
    /*时间归零*/
    void reset(){start_time=clock();}
};
#define maxSortNum 4    /*定义排序算法的个数(种类)*/
class CCompositor
{     int *a;
public:
    CCompositor(){a=NULL;}
    ~CCompositor(){delete []a;}
    void FileMenu();
    void Initional(int i);
    void GetFile(ifstream&is,int size);
    void doCompose(int n);
    void sort_1();
    void sort_2();
    void sort_3();
    void sort_4();
};
typedef void (CCompositor::*sort)();
sort g_x[] = {CCompositor::sort_1, CCompositor::sort_2, CCompositor::sort_3, CCompositor::sort_4};
struct SortStruct
{     int m_iIndex;    //索引
char* m_pChoice; //文件类型
char* m_pFile;     //文件路径
int m_iInfoSize; //文件大小
};
SortStruct sortArr[]={
    1, \"      1. 数据长度20个,   顺序\n\",    \"order20.txt\",            20,
        2, \"      2. 数据长度200个,  顺序\n\",    \"order200.txt\",            200,
        3, \"      3. 数据长度2000个, 顺序\n\",      \"order2000.txt\",            2000,
        4, \"      4. 数据长度20个,   逆序\n\",      \"unOrder20.txt\",            20,
        5, \"      5. 数据长度200个,  逆序\n\",      \"unOrder200.txt\",            200,
        6, \"      6. 数据长度2000个, 逆序\n\",      \"unOrder2000.txt\",        2000,
        7, \"      7. 数据长度20个,   随机\n\",      \"noOrder20.txt\",            20,
        8, \"      8. 数据长度200个,  随机\n\",      \"noOrder200.txt\",            200,
        9, \"      9. 数据长度2000个, 随机\n\",      \"noOrder2000.txt\",        2000,
        10,\"      10.数据长度20个,   部分排序\n\",\"partlyOrder20.txt\",        20,
        11,\"      11.数据长度200个,  部分排序\n\",\"partlyOrder200.txt\",        200,
        12,\"      12.数据长度200个,  部分排序\n\",\"partlyOrder2000.txt\",    2000,
};
void CCompositor::sort_1()
{     //增加代码,完成你的算法
}
void CCompositor::sort_2()
{     //增加代码,完成你的算法
}
void CCompositor::sort_3()
{     //增加代码,完成你的算法
}
void CCompositor::sort_4()
{     //增加代码,完成你的算法
}
void CCompositor::GetFile(ifstream&is,int size)
{     //if(!is)exit(1);
    delete a;a=NULL;
    a=new int[size];
    for(int i=0;i<size;i++)
        is>>a[i];
}
void CCompositor::FileMenu()
/*列出所有不同类型的数据*/
{     cout<<\"         算法比较数据文件目录\n\";
cout<<\"      ——————————————\"<<endl;
for (int i=0;i<sizeof(sortArr)/sizeof(SortStruct);i++)
{
    cout<<sortArr[i].m_pChoice;
}
cout<<\"请选择...\";
} void CCompositor::Initional(int i)
/*根据不同的文件数据进行数据加载*/
{     ifstream is;
is.open(sortArr[i-1].m_pFile);
GetFile(is,sortArr[i-1].m_iInfoSize);
is.close();
}
int _tmain(int argc, _TCHAR* argv[])
{     CCompositor compose;
compose.FileMenu();
int choice;cin>>choice;
compose.Initional(choice);
Timer time;
for(int j=0;j<sizeof(g_x)/4;j++)
{
    g_x[j];   
    time.elaspe();
    time.reset();
}
return 0;
}


不知道这个有用没

效率比较可以用模板的。

参与的数据也应该是多种

#4
myajax952006-09-25 13:52
应该差不多,我把它改成MFC下的,另外算效率的时候我再加上单步演示的算出各种算法各交换多少次。
#5
woodhead2006-09-26 16:10
三个基本排序,这段时间没什么长进,别的还不行。
高效排序明天吧。


[CODE]//end 是超尾

/*插入排序
最好时间复杂度O(n),最坏时间复杂度O(n^2),随机序列的复杂度接近后者。*/

template <class T>
void insertionsort(T *begin, T *end)
{
T *p, *q;
T tmp;
for(p=begin+1; p!=end; p++)
{
tmp = *p;
for(q=p; q!=begin && tmp<*(q-1); q--)
*q = *(q-1);
*q = tmp;
}
}
/*选择排序
最好最坏复杂度都是O(n^2),优点是移动次数较少*/

template <class T>
void selectionsort(T *begin, T *end)
{
T *p, *q, *least;
for(p=begin; p!=end-1; p++)
{
for(q=p+1,least=p; q!=end; q++)
if(*q < *least)
least = q;
if(p != least)
swap(*p, *least);
}
}

/*冒泡排序
时间复杂度是O(n^2),缺点是移动次数较多,认为是三种基本排序中最差的。*/

template <class T>
void bubblesort(T *begin, T *end)
{
T *p, *q;
end--;
for(p=begin; p!=end; p++)
for(q=end; q>p; q--)
if(*q < *(q-1))
swap(*q, *(q-1));
}[/CODE]
#6
woodhead2006-09-27 11:56
[CODE]template <class T>
inline void movedown(T *data, int first, int last)
{
int largest = 2*first + 1;
while(largest <= last)
{
if(largest<last && data[largest]<data[largest+1])
largest++;
if(data[first] < data[largest])
{
swap(data[first], data[largest]);
first = largest;
largest = largest*2 + 1;
}
else
break;
}
}

template <class T>
void heapsort(T *begin, T *end)
{
int size = end - begin;
for(int i=size/2-1; i>=0; i--)
movedown(begin, i, size-1);
for(int j=size-1; j>0; j--)
{
swap(*begin, *(begin+j));
movedown(begin, 0, j-1);
}
}[/CODE]
#7
live412006-09-27 12:01
以下是引用myajax95在2006-9-25 13:52:36的发言:
应该差不多,我把它改成MFC下的,另外算效率的时候我再加上单步演示的算出各种算法各交换多少次。

有没有MFC的变量类型说明, 我一直没分清.

#8
wfpb2006-09-27 12:53

myajax:你的那个首页有点问题,比如我双击以后进入hannuo,然后点首页返回,再点一下其他地方,然后再点hannuo就会发现,hannuo上没有焦点。

#9
woodhead2006-09-27 13:54
我的关于性能测试的想法

先定义一个基类Action,定义比较,移动的方法,同时有记录的变量。

[CODE]template <class T>
class Action
{
public:
pair<int,int> result;

Action() { result.first = 0; result.second = 0; }

bool lessthan(T &a, T &b)
{
result.first++;
return a < b;
}

void move(T &dest, T &source)
{
dest = source;
result.second++;
}

void Swap(T &a, T &b)
{
swap(a, b);
result.second += 3;
}
};[/CODE]

然后每种排序定义为一个由Action派生的类型,其中的比较,移动用基类的方法,如
[CODE]template <class T>
class InsertionSort : public Action<T>
{
void insertionsort(T *begin, T *end)
{
T *p, *q;
T tmp;
for(p=begin+1; p!=end; p++)
{
move(tmp, *p); //--
for(q=p; q!=begin && lessthan(tmp, *(q-1)); q--) //--
move(*q, *(q-1)); //--
move(*q, tmp); //--
}
}
public:

pair<int,int> operator()(T *begin, T *end)
{
Action<T>::result.first = 0;
Action<T>::result.second = 0;
insertionsort(begin, end);
return Action<T>::result;
}

};[/CODE]

[CODE]template <class T>
class HeapSort : public Action<T>
{
void movedown(T *data, int first, int last)
{
int largest = 2*first + 1;
while(largest <= last)
{
if( largest<last && lessthan(data[largest],data[largest+1]) ) //--
largest++;
if( lessthan(data[first], data[largest]) ) //--
{
Swap(data[first], data[largest]); //--
first = largest;
largest = largest*2 + 1;
}
else
break;
}
}
void heapsort(T *begin, T *end)
{
int size = end - begin;
for(int i=size/2-1; i>=0; i--)
movedown(begin, i, size-1);
for(int j=size-1; j>0; j--)
{
Swap(*begin, *(begin+j)); //--
movedown(begin, 0, j-1);
}
}
public:
pair<int,int> operator()(T *begin, T *end)
{
Action<T>::result.first = 0;
Action<T>::result.second = 0;
heapsort(begin, end);
return Action<T>::result;
}
};[/CODE]

我又加了一个函数,这个也许没有必要。
[CODE]template <class T, class U>
pair<int,int> Test(T *begin, T *end, U func)
{
return func(begin, end);
}[/CODE]

测试的主函数,
[CODE]int main()
{
const int N = 1000;
int ar[N], br[N];

for(int i=0; i<N; i++)
ar[i] = br[i] = Random::get().random();

for(int i=0; i<N; i++)
cout<<ar[i]<<' ';
cout<<endl;

pair<int, int> performance = Test(ar, ar+N, HeapSort<int>());
for(int i=0; i<N; i++)
cout<<ar[i]<<' ';
cout<<endl;
cout<<"\nheapsort\ncompare "<<performance.first<<"\nmove "<<performance.second<<endl;

performance = Test(br, br+N, InsertionSort<int>());
for(int i=0; i<N; i++)
cout<<ar[i]<<' ';
cout<<endl;
cout<<"\ninsertionsort\ncompare "<<performance.first<<"\nmove "<<performance.second<<endl;
cin.get();
return 0;
}[/CODE]

在 dev cpp编译通过,vc6不知道怎么样。

#10
wfpb2006-09-28 07:47
woodhead可以试着尽量不用T*
这样,很多时候就必须是数组了
比如容器什么的(一些STL容器),就不能用了

还是学着泛型编程上的那样做吧,一般化些。

PS:虽然我也是才开始看这本书,呵呵,不过觉得它上面说的很有道理
#11
woodhead2006-09-28 19:01
怎么实现迭代器还不会,另外上面的heapsort只能用数组。
#12
wfpb2006-09-29 17:01
myajax95又消失了
#13
myajax952006-09-30 05:38
这星期比较忙,周末也不在,可能下周开始。wfpb说的list control那个问题我看到了。大概是少设了一个always show selection的参数。
同时我正在作一个排序的UI上用到的显示没个数据的小方块的控件。
#14
wfpb2006-10-06 21:52
实话,这种项目既然没有策划人,就应该有领头人,myajax95,等你忙完了这阵子,再就要真正的搞一场了。
#15
woodhead2006-10-07 14:23
快速排序已经有了,就不再写了。


[CODE]template <class T>
class MergaSort: public Action<T>
{
T *p, *tmp;

void mergasort(int begin, int end)
{
int middle;
if(begin < end-1)
{
middle = (begin + end)/2;
mergasort(begin, middle);
mergasort(middle, end);
merga(begin, middle, end);
}
}

void merga(int begin, int middle, int end)
{
int i = 0; //tmp* index
int i1 = begin;
int i2 = middle;

while(i1!=middle && i2!=end)
{
if(lessthan(p[i1], p[i2]))
move(tmp[i++], p[i1++]);
else
move(tmp[i++], p[i2++]);
}

while(i1 < middle)
move(tmp[i++], p[i1++]);
while(i2 < end)
move(tmp[i++], p[i2++]);

for(i=0,i1=begin; i1!=end; i++,i1++)
move(p[i1], tmp[i]);
}

public:

pair<int,int> operator()(T *begin, T *end)
{
p = begin;
int size = end - begin;
tmp = new T[size];
mergasort(0,size);
delete[]tmp;
return Action<T>::result;
}

};[/CODE]

感觉移动次数太多,不知道有没有错误。

#16
wfpb2006-10-08 23:19
我这段时间在看泛型编程,有时间我试着把它改成泛型的,锻炼一下。
#17
wfpb2006-10-09 07:28

程序代码:

//end  是超尾


/*插入排序
最好时间复杂度O(n),最坏时间复杂度O(n^2),随机序列的复杂度接近后者。*/


template <class BidirectionalIterator>
//因为需要迭代器的有(++、--、=、!=)这几个功能,所以需要BinaryIterator这种concept
void insertionsort(BidirectionalIterator begin, BidirectionalIterator end)
{
    BidirectionalIterator p, q;
    typedef  typename iterator_traits<BidirectionalIterator>::value_type value_type;  //迭代器所指的对象的型别
    value_type tmp;
    begin++;
    p=begin;
    begin--;
    for(; p!=end; p++)
    {
        tmp = *p;
        for(q=p; q!=begin && tmp<*(q-1); q--)
            *q = *(q-1);
        *q = tmp;
    }
}


/*选择排序
最好最坏复杂度都是O(n^2),优点是移动次数较少*/


template <class BidirectionalIterator>    //同上
void selectionsort(BidirectionalIterator begin,BidirectionalIterator end)
{
    BidirectionalIterator p, q, least;
    end--;
    BidirectionalIterator end_It=end;
    end++;
    for(p=begin; p!=end_It; p++)
    {
        for(q=p+1,least=p; q!=end; q++)
            if(*q < *least)
                least = q;
        if(p != least)
            swap(*p, *least);
    }
}


/*冒泡排序
时间复杂度是O(n^2),缺点是移动次数较多,认为是三种基本排序中最差的。*/


template <class BidirectionalIterator>
void bubblesort(BidirectionalIterator begin, BidirectionalIterator end)
{
    BidirectionalIterator p, q;
    end--;
    for(p=begin; p!=end; p++)
        for(q=end; q>p; q--)
            if(*q < *(q-1))
                swap(*q, *(q-1));
}


我没有使用Random Access Iterator,因为这里使用Bidirectional Iterator就足够了。

[此贴子已经被作者于2006-10-9 14:16:26编辑过]

#18
wfpb2006-10-09 07:38
value_type是每个都会有的,iterator为每个预定义的Iterator都typedef好了。也为指针特化了。所以可以直接使用。
template<class It>
struct iterator_traits;
template<class T>
struct iterator_traits<T *>;
#19
wfpb2006-10-09 07:52


template<class RandomAccessIterator,class Distance>
void movedown(RandomAccessIterator data, Distance first,Distance last)
{
    Distance largest = 2*first + 1;
    while(largest <= last)
    {
        if( largest<last && (*(data+largest)<*(data+largest+1)) ) //--
            largest++;
        if(*(data+first)<*(data+largest)) //--
        {
            swap(*(data+first), *(data+largest)); //--
            first = largest;
            largest = largest*2 + 1;
        }
        else
            break;
    }
}



template<class RandomAccessIterator>
void heapsort(RandomAccessIterator begin,RandomAccessIterator end)
{
    typedef typename iterator_traits<RandomAccessIterator>::distance_type distance_type;
    distance_type size = end - begin;
    for(distance_type i=size/2-1; i>=0; i--)
        movedown(begin, i, size-1);
    for(distance_type j=size-1; j>0; j--)
    {
        swap(*begin, *(begin+j)); //--
        movedown(begin, 0, j-1);
    }
}





---------------------------------------------------------------------------
To Woodhead:
我应该没有改变你的意思吧~!
不知道有没有哪里疏忽了,如果发现就在这个帖子回复吧!

[此贴子已经被作者于2006-10-9 17:02:35编辑过]

#20
woodhead2006-10-09 14:37
试过能运行就可以吧,我这方面确实不行。
#21
小花2006-10-11 12:57

出来诈到,顶顶

#22
myajax952006-10-16 01:15

本想写一个class可以显示图标,在排序交换的时候动态显示每一步,写了一下发现有几个地方我还不太清楚,可能还要研究一会,不好意思让大家久等了。

#23
woodhead2006-10-17 17:48
没有办法,帮不上。
#24
myajax952006-10-18 11:03
只有本站会员才能查看附件,请 登录

凑合了一个流程图控件,很不理想。不过可以在这个基础上把他写完了。谁有兴趣的话可以接着这个写,否则我周末把它补完。
#25
myajax952006-10-18 11:05

忘了说了,这个控件可以实现简单的颜色变化,例如当前的流程图元件被选中了,可以设CFlowChart::SetState(),这样它的颜色就变了。正好可以用这种方法显示排序时指针的移动和数据的交换。

#26
wfpb2006-10-19 19:04
哎,又是你一个人做啊。。。
#27
myajax952006-10-19 23:07
希望能一起作,24楼的帖子里可以下载原程序,接着改viewsorting.cpp和viewsorting.h就可以了。不过我个人也有N样东西想通过这个例子来试验,自己作也可以。
#28
wfpb2006-10-20 08:58
可是一起做的话,你的思想我还没理解,怎么个动态显示 排序过程  啊?
#29
myajax952006-10-20 09:10
就是说有N种排序方法,在图上显示成N行。每行有M个元素。用户选开始的时候被比较的元素就由灰色变成倍选重的颜色,例如黄色。这样分部进行的时候每个元素如何交换的就看的很清楚了。我的这个Flow Chart的class写的不好,只能变一种颜色。回头作一个可以变多种颜色的。元素被选中的时候一个颜色,被交换的时候领一个颜色。
#30
myajax952006-10-24 14:53
只有本站会员才能查看附件,请 登录


[此贴子已经被作者于2006-10-25 2:44:33编辑过]

#31
xiaojiejie2006-10-26 01:11
怎么没人带头啊 ?晕类!有没一起学习的加我QQ:578757691
#32
woodhead2006-11-03 13:21
to ajax95

感觉这样做分步演示,计算部分写起来比较复杂。
用线程也许更容易一些,把计算部分放到一个单独的线程,和控制线程同步。vc中应该有控制多线程的方法吧。
例如这样一个结构。(我多线程也没写过,不熟悉)

[CODE]
vector<int> container;
bool finish;

DWORD WINAPI algorithmThreadFunc( LPVOID lpParam );
void mySort(...);

int main() //control thread
{

init(container);

//Create algorithm thread
......

finish = false;

while(!finish)
{
//同步,move to algorithm thread
//等待计算线程信号量
......

//然后
waitSomeTime();
draw();//在画面更新每一步结果
}

......

}


DWORD WINAPI algorithmThreadFunc( LPVOID lpParam )
{
......
mySort(...);
finish = true;
......
}


void mySort(...) //对container操作
{
......
......
//synchronize after somewhere move or swap action
//self block and move to control thread
......
......
}

[/CODE]
#33
junlongsina2006-11-29 01:05
太深奥了
#34
jels10871012006-11-29 22:42
看不懂啊,想帮也帮不上~~~
#35
小巴2006-11-30 14:05
真爽!这些比较吸引我 我得尽快学了 跟上你们的脚步
#36
tilams2006-12-07 13:37
    看来要努力学习C++了
#37
lyle32007-04-04 21:50
看不懂在做什么。。。
我刚开始学C++~~
#38
jiushiwo2007-04-16 10:02
还要好好学习啊,都看不懂
1