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

【栈是后进先出的】

先来定义栈的数据结构:

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

①、栈的初始化:

#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++中的类就可以保护内部的数据结构不遭受破坏。

原文地址:https://www.cnblogs.com/webor2006/p/5229118.html