多态&指针访问虚函数&不能被继承的类&快速排序&N皇后问题&插入排序&堆排序&merge归并排序&栈上生成对象&两个栈实现一个队列

来源:互联网 发布:mfc编程实例 2008 编辑:程序博客网 时间:2024/06/13 00:10

多态

/*    1. 要想实现覆盖(重写)父类必须声明为virtual,子类可以不声明为virtual.-->FunB()    2. 派生类重写基类的虚函数实现多态,要求函数名、参数列表、返回值完全相同。(协变除外)    3. 基类中定义了虚函数,在派生类中该函数始终保持虚函数的特性。    4. 只有类的非静态成员函数才能定义为虚函数,静态成员函数不能定义为虚函数。    5. 如果在类外定义虚函数,只能在声明函数时加virtual关键字,定义时不用加。    6. 构造函数不能定义为虚函数,虽然可以将operator=定义为虚函数,但最好不要这么做,使用时容    易混淆    7. 不要在构造函数和析构函数中调用虚函数,在构造函数和析构函数中,对象是不完整的,可能会    出现未定义的行为。    8. 最好将基类的析构函数声明为虚函数。(析构函数比较特殊,因为派生类的析构函数跟基类的析构    函数名称不一样,但是构成覆盖,这里编译器做了特殊处理)    9. 虚表是所有类对象实例共用的*/#include<iostream>using namespace std;class CBase{public:    virtual void FunA(int a)    {        cout << "CBase::FunA()" << endl;    }    void FunB(int a)    {        cout << "CBase::FunB()" << endl;    }    virtual void FunC(int a1)    {        cout << "CBase::FunC()" << endl;    }    virtual void FunD(int a)    {        cout << "CBase::FunD()" << endl;    }};class CDerived :public CBase{public:    virtual void FunA(int a)    {        cout << "CDerived::FunA()" << endl;    }    virtual void FunB(int a)    {        cout << "CDerived::FunB()" << endl;    }    void FunC(int a1)    {        cout << "CDerived::FunC()" << endl;    }    virtual void FunD(int a1, int a2)    {        cout << "CDerived::FunD()" << endl;    }};int main(){    CBase* pBase = new CDerived;    pBase->FunA(0); //CDerived::FunA()    pBase->FunB(0);//CBase::FunB()    pBase->FunC(0);//CDerived::FunC()    pBase->FunD(0);//CBase::FunD()//  pBase->FunD(0,0);//编译报错error C2660: “CBase::FunD”: 函数不接受 2 个参数    system("pause");    return 0;}/*    1. 覆盖:        1.不同的作用域(分别位于基类和派生类中)         2.函数名称完全相同         3.参数列表完全相同         4.基类函数必须是虚函数        5.返回值类型相同(协变除外)    2. 重载:        1.具有相同的作用域         2.函数名字相同         3.参数类型顺序或数目不同(包括const和非const参数)         4.virtual关键字可有可无    3. 隐藏:        1.派生类的函数与基类的函数同名,但是参数列表有所差异。           此时不论有没有virtual关键字,基类的函数在派生类中都将被隐藏。        2.派生类的函数与基类的函数同名,参数列表也相同,但是基类函数没有          virtual关键字。基类的函数也会被隐藏。 */

指针访问类里面的虚函数

#include<iostream>using namespace std;class A{public:    virtual void FunA()    {        cout << "我是A的FunA" << endl;    }    virtual void FunB()    {        cout << "我是A的FunB" << endl;    }};class B :public A{public:    virtual void FunA()    {        cout << "我是B的A" << endl;    }    virtual void FunB()    {        cout << "我是B的B" << endl;    }    virtual void FunC()    {        cout << "我是B的FunC" << endl;    }    virtual void FunD()    {        cout << "我是B的FunD" << endl;    }};/*定义一个有10个指针的数组tmp,该指针是指向一个整形数: int  *tmp[10];一个指向有10个整形数数组的指针tmp:  int  (*tmp)[10];一个指向函数的指针,该函数有一个整型参数并返回一个整型数:int (*fun)(int);一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数:  int(*fun[10])(int);*/typedef void(*Fun)(void);int main(){    B b;    A a;    Fun pFun[3];    for (int i = 0; i < 4; i++)    {        pFun[i] = (Fun)*((int *)*(int *)&b + i);        /*            *(int*)&b:取到虚函数表的首地址            *(int *)*(int *)&b:取到第一个函数的函数指针        */        pFun[i]();    }    /*        我是B的A        我是B的B        我是B的FunC        我是B的FunD        请按任意键继续. . .    */    system("pause");}

设计一个不能被继承的类

/*    设计一个不能被继承的类    1. 利用友元类可以访问类里所有成员的特性    2. 利用虚基类的构造函数需要由最终的子类调用完成构造的特性*/#include<iostream>using namespace std;class Grand{    friend class Parent;private:    Grand()    {}    ~Grand()    {}};class Parent:virtual public Grand{public:    Parent()    {}    ~Parent()    {}};/*    设计一个不能被继承的类.cpp(30): error C2248: “Grand::Grand”: 无法访问 private 成员(在“Grand”类中声明)    设计一个不能被继承的类.cpp(14) : 参见“Grand::Grand”的声明    设计一个不能被继承的类.cpp(9) : 参见“Grand”的声明    此诊断出现在编译器生成的函数“Son::Son(void)”中*/class Son:public Parent{};int main(){    Son s;    system("pause");}/*    1. 友元不属于任何类,但需要在类的内部声明,声明时需要加friend关键字    2. 友元函数可访问类的私有成员,但不是类的成员函数;    3. 友元函数不能用const修饰;    4. 友元函数可以在类定义的任何地方声明,不受类访问限定    符限制;    5. 函数可以是多个类的友元函数;    6. 友元函数的调用与普通函数的调用和原理相同;    友元类:友元类的所有成员函数都可以是另一个类的友元函数,    都可以访问另一个类中的非公有成员;*//*    友元的优缺点    优点:提高了程序运行效率    缺点:破坏了类的封装性和隐藏性    注意:    友元关系不能继承;    友元关系是单向的,不具有交换性;    友元关系不能传递;*/

快速排序

这里写图片描述
  选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,而冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法

#include<iostream>using namespace std;//普通法int partion1(int *arr, int left, int right){    //快排若选用左边的为基准值,则指针应当从右边开始走    //反之若选右边的则应当从左边走    /*        如本例,若从左边开始走则        2, 1, 6, 3, 4, 5, 9, 5, 0        2  1  0*  3  4  5  9  5  *6        这时begin3位置,end也会走到3位置,循环结束        交换arr[left]与arr[begin]        2  1  0  3  4  5  9  5  6        3  1  0  2  4  5  9  5  6        结果不对。        arr[end]>=key        arr[begin] <=key        必须都是大于等于或小于等于号,不能没有等号,    */    int key = arr[left];    int begin = left;    int end = right-1;    while (begin < end)    {        while (begin<end&&arr[end]>=key)            --end;        while (begin < end&&arr[begin] <=key)            ++begin;        if (begin < end)            swap(arr[begin], arr[end]);    }    swap(arr[begin], arr[left]);    return begin;}//挖坑法int partion2(int *arr, int left, int right){    int key = arr[left];    int end = right - 1;    int begin = left;    while (begin < end)    {        while (begin<end&&arr[end]>=key)            --end;        arr[begin] = arr[end];        while (begin < end&&arr[begin] <= key)            ++begin;        arr[end] = arr[begin];    }    arr[begin] = key;    return begin;}//极简双指针法int partion3(int *arr, int left, int right){    int pCur = left;    int pPre = left - 1;    /*    例         2, 1, 6, 3, 4, 5, 9, 5, 4         2  1  3  *6  #4  5  9  5  4         2  1  3  *4  4  5  9  5  6    */    while (pCur < right)    {        while (arr[pCur] < arr[right - 1] && ++pPre != pCur)            swap(arr[pCur], arr[pPre]);        pCur++;    }    swap(arr[++pPre], arr[right - 1]);    return pPre;}void qSort(int *arr,int left, int right){    if (right - left < 2)        return;    if (left < right)    {        int Boundary = partion3(arr, left, right);        qSort(arr, left, Boundary);        qSort(arr, Boundary+1, right);    }}int main(){    int arr[] = { 2, 1, 6, 3, 4, 5, 9, 5, 0 };    int len = sizeof(arr) / sizeof(arr[0]);    qSort(arr, 0,len);    for (int i = 0; i < len; i++)    {        cout << arr[i] << " ";    }    cout << endl;    system("pause");}

N皇后问题

/*    1.用一个数组保存之前放置皇后的位置,如arr[i]=j,则代表第i行第j列放置了皇后    2. 以行为基准,行每次自增,判断列是否放置合法。*/#include<iostream>using namespace std;bool isleagle(int *arr, int i, int j){    for (int k = 0; k < i; k++)    {        if (j == arr[k] || abs(arr[k] - j) == abs(i - k))        {            return false;        }    }    return true;}int getNum(int i, int *arr, int n){    if (i == n)        return 1;    int res = 0;    for (int j = 0; j < n; j++)    {        if (isleagle(arr, i, j))        {            arr[i] = j;            //每次递归递归到i==n说明有一条路了,然后返回到上一层,            //上一层的i是n-1这时,j再换一个格子就是j++,然后继续            //递归到n则又有一条路。于是所有路经都计算到了            res += getNum(i + 1, arr, n);        }    }    return res;}int gethuanghou(int n){    if (n < 1)        return 0;    int *arr = new int[n];    return getNum(0, arr, n);}int main(){    int n;    while (cin >> n)        cout << gethuanghou(n) << endl;    system("pause");    return 0;}

插入排序

#include<iostream>using namespace std;void InsertSort(int *arr, int len){    if (len < 2)        return;    for (int i = 0; i < len; i++)    {        int j = i - 1;        int key = arr[i];        while (j>-1 && arr[j]>key)        {            arr[j + 1] = arr[j];            --j;        }        arr[j + 1] = key;    }}int main(){    int arr[] = { 2, 3, 1, 5, 12, 3, 7, 3, 9, 3, 0, 2 };    int len = sizeof(arr) / sizeof(arr[0]);    InsertSort(arr, len);    for (int i = 0; i < len; i++)    {        cout << arr[i] << " ";    }    cout << endl;    system("pause");    return 0;}

堆排序

#include<iostream>using namespace std;class Heap_Sort{public:    void Sort(int *arr, int len)    {        _Build_Heap(arr, len);        while (len > 1)        {            swap(arr[0], arr[len - 1]);            len--;            _AdjustDown(arr,0,len);         }    }private:    void _Build_Heap(int *arr, int len)    {        for (int i = ((len - 2) >> 1); i >= 0; i--)        {            _AdjustDown(arr, i,len);        }    }    void _AdjustDown(int *arr, int root,int size)    {        int parent = root;        int child = 2 * parent + 1;        while (child <size)        {            if (child < size&&arr[child] < arr[child + 1])                child += 1;            if (child < size&&arr[parent] < arr[child])            {                swap(arr[parent], arr[child]);                parent = child;                child = 2 * parent + 1;            }            else                break;        }    }};int main(){    int arr[] = { 5, 3, 1, 7, 4, 0, 6, 8, 4, 7 };    int len = sizeof(arr) / sizeof(arr[0]);    Heap_Sort s;    s.Sort(arr, len);    for (int i = 0; i < len; i++)        cout << arr[i] << " ";    cout << endl;    system("pause");}

冒泡排序

#include<iostream>using namespace std;//注意第二个条件是j<len-i-1void BubbleSort(int *arr, int len){    if (len < 2)        return;    bool flag = true;     for (int i = 0; i < len; i++)    {        for (int j = 0; j < len - i - 1; j++)        {            if (arr[j] >arr[j + 1])            {                swap(arr[j], arr[j + 1]);                flag = false;            }        }        if (flag)            return;    }}int main(){    int arr[] = { 2, 3, 1, 5, 12, 3, 7, 3, 9, 3, 0, 2 };    int len = sizeof(arr) / sizeof(arr[0]);    BubbleSort(arr, len);    for (int i = 0; i < len; i++)    {        cout << arr[i] << " ";    }    cout << endl;    system("pause");    return 0;}

merge归并排序

#include<iostream>#include<cassert>using namespace std;void Merge(int *arr, int left,int mid, int right, int *temp){    int begin1 = left;    int end1 = mid;    int begin2 = mid + 1;    int end2 = right;    int idx = left;    while (begin1 <= end1&&begin2<=end2)    {        if (arr[begin1] < arr[begin2])            temp[idx++] = arr[begin1++];        else            temp[idx++] = arr[begin2++];    }    while (begin1<=end1)        temp[idx++] = arr[begin1++];    while (begin2<=end2)        temp[idx++] = arr[begin2++];    for (int i = left; i<=right; i++)        arr[i] = temp[i];}void _Merge_Sort(int *arr, int left, int right, int *temp){    if (right > left)    {        int mid = left + ((right - left) >> 1);        _Merge_Sort(arr, left, mid, temp);        _Merge_Sort(arr, mid + 1, right, temp);        Merge(arr, left, mid,right, temp);    }}void Merge_Sort(int *arr, int left, int right){    assert(right - left > 1);    int *temp = new int[right - left + 1];    _Merge_Sort(arr, left, right, temp);    delete[]temp;}int main(){    int arr[] = { 2, 3, 45, 2, 5, 1, 8, 5, 2, 3, 0 };    int len = sizeof(arr) / sizeof(arr[0]);    Merge_Sort(arr, 0, len-1);    for (int i = 0; i < len; i++)    {        cout <<arr[i] << " ";    }    cout << endl;    system("pause");}

只能在栈上生成对象

/*只有使用new运算符,对象才会建立在堆上,因此,只要禁用new运算符就可以实现类对象只能建立在栈上。将operator new()设为私有即可。代码如下:*/#include<iostream>using namespace std;class Base{private:    void *operator new(size_t);    void operator delete(void *);public:    Base()    {}    ~Base();};int main(){    Base *ptr = new Base;}

只能在堆上生成对象

/*容易想到将构造函数设为私有。在构造函数私有之后,无法在类外部调用构造函数来构造类对象,只能使用new运算符来建立对象。然而,前面已经说过,new运算符的执行过程分为两步,C++提供new运算符的重载,其实是只允许重载operator new()函数,而operator()函数用于分配内存,无法提供构造功能。因此,这种方法不可以。当对象建立在栈上面时,是由编译器分配内存空间的,调用构造函数来构造栈对象。当对象使用完后,编译器会调用析构函数来释放栈对象所占的空间。编译器管理了对象的整个生命周期。如果编译器无法调用类的析构函数,情况会是怎样的呢?比如,类的析构函数是私有的,编译器无法调用析构函数来释放内存。所以,编译器在为类对象分配栈空间时,会先检查类的析构函数的访问性,其实不光是析构函数,只要是非静态的函数,编译器都会进行检查。如果类的析构函数是私有的,则编译器不会在栈空间上为类对象分配内存。因此,将析构函数设为私有,类对象就无法建立在栈上了。代码如下:class  A{public :    A(){}    void  destory(){ delete   this ;}private :    ~A(){}};*//*试着使用A a;来建立对象,编译报错,提示析构函数无法访问。这样就只能使用new操作符来建立对象,构造函数是公有的,可以直接调用。类中必须提供一个destory函数,来进行内存空间的释放。类对象使用完成后,必须调用destory函数。上述方法的一个缺点就是,无法解决继承问题。如果A作为其它类的基类,则析构函数通常要设为virtual,然后在子类重写,以实现多态。因此析构函数不能设为private。还好C++提供了第三种访问控制,protected。将析构函数设为protected可以有效解决这个问题,类外无法访问protected成员,子类则可以访问。另一个问题是,类的使用很不方便,使用new建立对象,却使用destory函数释放对象,而不是使用delete。(使用delete会报错,因为delete对象的指针,会调用对象的析构函数,而析构函数类外不可访问)这种使用方式比较怪异。为了统一,可以将构造函数设为protected,然后提供一个public的static函数来完成构造,这样不使用new,而是使用一个函数来构造,使用一个函数来析构。代码如下,类似于单例模式:*/#include<iostream>using namespace std;class Base{private:    Base()    {}    ~Base()    {}public:    static Base* getInstance()    {        return new Base;    }    void  destory()    {        delete   this;    }};int main(){    Base *b = Base::getInstance();}

两个栈实现一个队列

#include<iostream>#include<stack>using namespace std;template<class T>class StackQueue{public:    void Push(T data)    {        //Spush的入栈就相当于入队        Spush.push(data);    }    void Pop()    {        /*            如果Spop为空,则一直将sPush里面的元素压入Spop中            直到Spush为空,然后Spop弹出,就相当于入队            如果Spop不为空则直接弹出,就相当于出队        */        if (Spop.empty())        {            while (!Spush.empty())            {                Spop.push(Spush.top());                Spush.pop();            }        }        Spop.pop();    }    T Front()    {        if (Spop.empty())        {            while (!Spush.empty())            {                Spop.push(Spush.top());                Spush.pop();            }        }        return Spop.top();    }    bool empty()    {        return Spop.empty() && Spush.empty();    }private:    stack<T> Spush;    stack<T> Spop;};int main(){    StackQueue<int> q;    q.Push(1);    q.Pop();    q.Push(2);    q.Push(3);      q.Pop();    q.Pop();    cout << q.empty() << endl;    //cout << q.Front() << endl;    system("pause");    return 0;}

有getMin功能的栈

#include<iostream>#include<stack>#include<cstdio>using namespace std;/*    注意        1. 在得到Min值时,首先要判断stack是否为空,不为空再getMin        2. Min在pop时要判断pop的元素是否为当前的最小元素*/template<class T>class MinStack{public:    T Top()    {        return _stack.top();    }    void Push(T data)    {        _stack.push(data);        if (_Min.empty() || data < _Min.top())        {            _Min.push(data);        }    }    bool Empty()    {        return _stack.empty();    }    void Pop()    {        if (_stack.top() == _Min.top())            _Min.pop();        _stack.pop();    }    T getMin()    {        //注意在getMin是要判断栈是否为空        if (_stack.empty())        {            return INT_MAX;        }        return _Min.top();    }private:    stack<T> _stack;    stack<T> _Min;};int main(){    /*MinStack<int> s;    s.Push(1);    s.Push(4);    s.Push(5);    s.Push(0);    cout << s.getMin() << endl;    cout << INT_MAX << endl;    system("pause");*/    MinStack<int> st;    char s[100];    int op;    while (scanf("%s", s) == 1 && strcmp(s, "END") != 0)     {        if (strcmp(s, "PUSH") == 0)         {            scanf("%d", &op);            st.Push (op);            printf("push=%d\n", op);        }        else if (strcmp(s, "POP") == 0)         {            op = st.Top();            st.Pop();            printf("pop=%d\n", op);        }        else if (strcmp(s, "TOP") == 0)         {            printf("top=%d\n", st.Top());        }        else if (strcmp(s, "MIN") == 0)         {            printf("min=%d\n", st.getMin());        }    }    return 0;}
阅读全文
3 0
原创粉丝点击