• 从一个实例看数据抽象与封装


    【栈是后进先出的】

    先来定义栈的数据结构:

    接下来定义栈的一些操作方法:

    ①、栈的初始化:

    #include <stdio.h>
    
    struct Link {//栈里面的数据结构由链表来表示
        int data;
        struct Link* next;
    };
    
    struct Stack {
        struct Link* head;//栈的头指针
        int size;//栈的大小
    };
    
    
    //栈的初始化
    void stackInit(struct Stack* stack) {
        stack->head = NULL;
        stack->size = 0;
    }
    
    int main(void) {
        return 0;
    }

    ②、往栈中压入一个数据:

    关于压栈的整个过程在之前学C时有讲解过,具体可以参考博文:http://www.cnblogs.com/webor2006/p/3481080.html

    下面具体实现:

    #include <stdio.h>
    #include <assert.h>
    #include <malloc.h>
    
    struct Link {//栈里面的数据结构由链表来表示
        int data;
        struct Link* next;
    };
    
    struct Stack {
        struct Link* head;//栈的头指针
        int size;//栈的大小
    };
    
    
    //栈的初始化
    void stackInit(struct Stack* stack) {
        stack->head = NULL;
        stack->size = 0;
    }
    
    //往栈中压入一个数据
    void stackPush(struct Stack* stack, const int data) {
        //首先产生一个新的结点
        struct Link* node;
        node = (struct Link*)malloc(sizeof(struct Link));
        assert(node != NULL);
        node->data = data;
        node->next = stack->head;
        stack->head = node;
        ++stack->size;
    }
    
    int main(void) {
        return 0;
    }

    ③、往栈中弹出一个数据:

    #include <stdio.h>
    #include <assert.h>
    #include <malloc.h>
    
    struct Link {//栈里面的数据结构由链表来表示
        int data;
        struct Link* next;
    };
    
    struct Stack {
        struct Link* head;//栈的头指针
        int size;//栈的大小
    };
    
    
    //栈的初始化
    void stackInit(struct Stack* stack) {
        stack->head = NULL;
        stack->size = 0;
    }
    
    //往栈中压入一个数据
    void stackPush(struct Stack* stack, const int data) {
        //首先产生一个新的结点
        struct Link* node;
        node = (struct Link*)malloc(sizeof(struct Link));
        assert(node != NULL);
        node->data = data;
        node->next = stack->head;
        stack->head = node;
        ++stack->size;
    }
    
    int isStackEmpty(struct Stack* stack) {
        return (stack->size == 0);
    }
    
    //往栈中弹出一个数据,能出栈返回1,否则返回0
    int stackPop(struct Stack* stack, int* data) {
        if(isStackEmpty(stack))
            return 0;
    
        struct Link* temp = stack->head;
        *data = stack->head->data;
        stack->head = stack->head->next;
        free(temp);
        --stack->size;
        
        return 1;
    }
    
    
    
    int main(void) {
        return 0;
    }

    ④、清除栈:

    #include <stdio.h>
    #include <assert.h>
    #include <malloc.h>
    
    struct Link {//栈里面的数据结构由链表来表示
        int data;
        struct Link* next;
    };
    
    struct Stack {
        struct Link* head;//栈的头指针
        int size;//栈的大小
    };
    
    
    //栈的初始化
    void stackInit(struct Stack* stack) {
        stack->head = NULL;
        stack->size = 0;
    }
    
    //往栈中压入一个数据
    void stackPush(struct Stack* stack, const int data) {
        //首先产生一个新的结点
        struct Link* node;
        node = (struct Link*)malloc(sizeof(struct Link));
        assert(node != NULL);
        node->data = data;
        node->next = stack->head;
        stack->head = node;
        ++stack->size;
    }
    
    int isStackEmpty(struct Stack* stack) {
        return (stack->size == 0);
    }
    
    //往栈中弹出一个数据,能出栈返回1,否则返回0
    int stackPop(struct Stack* stack, int* data) {
        if(isStackEmpty(stack))
            return 0;
    
        struct Link* temp = stack->head;
        *data = stack->head->data;
        stack->head = stack->head->next;
        free(temp);
        --stack->size;
        
        return 1;
    }
    
    //清除栈
    void clearStack(struct Stack* stack) {
        struct Link* temp;
        while(stack->head) {
            temp = stack->head;
            stack->head = stack->head->next;
            free(temp);
        }
        stack->size = 0;
    }
    
    int main(void) {
        return 0;
    }

    下面编写测试代码来对其进行测试:

    编译运行:

    上面用是C的方式来实现的,接下来改用C++的方式,首先声明栈的结构,这里用class来声明:

    #include <iostream>
    using namespace std;
    
    class Stack {
        struct Link {//栈里面的数据结构由链表来表示,这里用结构体来表示是由于默认它里面的成员是公有的,而类默认成员是私有的
            int data_;
            Link* next_;
        };
    private:
        Link* head_;//栈的头指针
        int size_;//栈的大小
    };
    
    int main(void) {
        return 0;
    }

    接着来实现栈的操作函数:

    ①、栈的初始化:C++中可以在类的构造时进行初始化:

    ②、往栈中压入一个数据:

    #include <iostream>
    using namespace std;
    
    class Stack {
        struct Link {//栈里面的数据结构由链表来表示,这里用结构体来表示是由于默认它里面的成员是公有的,而类默认成员是私有的
            int data_;
            Link* next_;
            Link(int data, Link* next):data_(data),next_(next)//结构体实际上就是类,所以也可以构造
            {
            }
        };
    public:
        Stack(): head_(NULL), size_(0) {
    
        }
    
        //往栈中压入一个数据
        void push(const int data) {
            //首先产生一个新的结点
            Link* node = new Link(data, head_);
            head_ = node;
            ++size_;
        }
    private:
        Link* head_;//栈的头指针
        int size_;//栈的大小
    };
    
    int main(void) {
        return 0;
    }

    ③、往栈中弹出一个数据:

    #include <iostream>
    using namespace std;
    
    class Stack {
        struct Link {//栈里面的数据结构由链表来表示,这里用结构体来表示是由于默认它里面的成员是公有的,而类默认成员是私有的
            int data_;
            Link* next_;
            Link(int data, Link* next):data_(data),next_(next)//结构体实际上就是类,所以也可以构造
            {
            }
        };
    public:
        Stack(): head_(NULL), size_(0) {
    
        }
    
        //往栈中压入一个数据
        void push(const int data) {
            //首先产生一个新的结点
            Link* node = new Link(data, head_);
            head_ = node;
            ++size_;
        }
    
        //判断栈是否为空栈
        bool isStackEmpty() {
            return (size_ == 0);
        }
    
        //往栈中弹出一个数据,能出栈返回true,否则返回false
        bool pop(int& data) {
            if(isStackEmpty())
                return false;
        
            struct Link* temp = head_;
            data = head_->data_;
            head_ = head_->next_;
            delete temp;
            --size_;
            
            return true;
        }
    
    private:
        Link* head_;//栈的头指针
        int size_;//栈的大小
    };
    
    int main(void) {
        return 0;
    }

    ④、清除栈:这个可以放到析构函数中~

    #include <iostream>
    using namespace std;
    
    class Stack {
        struct Link {//栈里面的数据结构由链表来表示,这里用结构体来表示是由于默认它里面的成员是公有的,而类默认成员是私有的
            int data_;
            Link* next_;
            Link(int data, Link* next):data_(data),next_(next)//结构体实际上就是类,所以也可以构造
            {
            }
        };
    public:
        Stack(): head_(NULL), size_(0) {
    
        }
    
        ~Stack() {
            Link* temp;
            while(head_) {
                temp = head_;
                head_ = head_->next_;
                delete temp;
            }
        }
    
        //往栈中压入一个数据
        void push(const int data) {
            //首先产生一个新的结点
            Link* node = new Link(data, head_);
            head_ = node;
            ++size_;
        }
    
        //判断栈是否为空栈
        bool isStackEmpty() {
            return (size_ == 0);
        }
    
        //往栈中弹出一个数据,能出栈返回true,否则返回false
        bool pop(int& data) {
            if(isStackEmpty())
                return false;
        
            struct Link* temp = head_;
            data = head_->data_;
            head_ = head_->next_;
            delete temp;
            --size_;
            
            return true;
        }
    
    private:
        Link* head_;//栈的头指针
        int size_;//栈的大小
    };
    
    int main(void) {
        return 0;
    }

    接下来进行测试:

    编译运行:

    对比用C方式实现,有如下不同:

    ①、栈的初始化放到了构造中,销毁放到了析造当中。

    ②、每个函数的调用不需要传递栈的地址,调用方式变为了stack.push(),写起来也更加自然一些。

    ③、用类的方式实现能够避免名称冲突,它的作用域是在类当中所以能有效的避免名称冲突,另外如果真出现还可以用namesapce解决,而用C的方式实现通常方法前面加了一个stack前缀来避免,如:stackPush、stackPop,如果不带前缀可能跟系统库函数的冲突比较大。

    ④、C++中用类表示栈能达到数据封装性,使得外部不能随意访问里面的私有成员;而C是没有封装性的,外部代码可以任意的修改它里面的数据,如下:

    运行就会出错了:

    所以可以看出C中存在一定的风险,而C++中的类就可以保护内部的数据结构不遭受破坏。

  • 相关阅读:
    20169306《网络攻击与防范》第八周学习总结
    20169306《网络攻击与防范》第七周学习总结
    20169306《网络攻击与防范》第六周学习总结
    20169306《网络攻击与防范》第五周学习总结
    20169306《网络攻击与防范》第四周学习总结
    SQL注入
    路径遍历漏洞
    sqlmap安装及简单使用——12.30
    margin,CSS边距重叠
    20169314 2016-2017-2《网络攻防》课程总结
  • 原文地址:https://www.cnblogs.com/webor2006/p/5229118.html
Copyright © 2020-2023  润新知