zoukankan      html  css  js  c++  java
  • 数据结构与算法分析(三)

    数据结构与算法分析(三)

    这一次,我们说一说三种比较简单的数据结构,是一维的,分别是:

    1.表

    2.栈

    3.队列

    1.表

    对于表而言,当然可以用数组来实现,插入和删除的时候会带来巨大的开销,因此更多的时候,我们都是采用"链表(linked list)"这种形式.

    链表有很多变种,但是最基础的,基本功能是相似的,通常为了方便,链表的头(header)我们会放一个哑节点.

    我们用ADT的方式实现.

    Linked.h

    #ifndef LIST_H
    #define LIST_H
    
    #include <iostream>
    
    using namespace std;
    
    struct ListNode;
    typedef int ElementType;
    typedef struct ListNode *PtrToNode;
    typedef PtrToNode List;
    typedef PtrToNode Position;
    
    List CreateList();
    int IsEmpty(List L);
    int IsLast(Position P, List L);
    Position Find(ElementType X, List L);
    void Delete(ElementType X, List L);
    Position FindPrevious(ElementType X, List L);
    void Insert(ElementType X, List L, Position P);
    void DeleteList(List L);
    Position Header(List L);
    Position First(List L);
    void Print(List L);
    
    struct ListNode{
        ElementType Element;
        Position Next;
    };
    
    List CreateList(){
        Position P = new ListNode;
        P->Next = nullptr;
        return P;
    }
    
    int IsEmpty(List L){
        return L->Next == nullptr;
    }
    
    int IsLast(Position P, List L){
        return P->Next == nullptr;
    }
    
    Position Find(ElementType X, List L){
        Position P = L->Next;
        while(P != nullptr && P->Element != X){
            P = P->Next;
        }
        return P;
    }
    
    void Delete(ElementType X, List L){
        Position P = L->Next, tmpCell;
        P = FindPrevious(X, L);
        if(!IsLast(P, L)){
            tmpCell = P->Next;
            P->Next = tmpCell->Next;
            delete tmpCell;
        }
    }
    
    Position FindPrevious(ElementType X, List L){
        Position P = L;
        while(P->Next != nullptr && P->Next->Element != X){
            P = P->Next;
        }
        return P;
    }
    
    void Insert(ElementType X, List L, Position P){
        Position tmpCell = new ListNode;
        tmpCell->Element = X;
        tmpCell->Next = P->Next;
        P->Next = tmpCell;
    }
    
    void DeleteList(List L){
        Position P, tmpCell;
    
        P = L->Next;
        L->Next = nullptr;
        while(P != nullptr){
            tmpCell = P->Next;
            delete P;
            P = tmpCell;
        }
    }
    
    Position Header(List L){
        return L;
    }
    
    Position First(List L){
        return L->Next;
    }
    
    void Print(List L){
        Position P = L->Next;
        while(P != nullptr){
            cout << P->Element << "->";
            P = P->Next;
        }
        cout << "nullptr" << endl;;
    }
    
    #endif // LIST_H
    
    

    我们将所有的操作都放在Linked.h头文件里,如果在程序中想要引用,直接 #include就好.

    ADT可分为"数据集""操作集",很符合"面向对象"的思想.

    数据集:

    存放数据,以及下一个结点的地址,

    struct Node{
    ElementType Element;
    Position Next;
    };

    操作集:

    1.创建链表CreateList

    2.元素插入Insert

    3.元素删除Delete

    4.查找元素位置Find

    5.删除链表DeleteList

    特地增加了一个Print(List L)函数,方便测试时候使用.

    2.栈

    栈也是一种非常常见的数据结构,应用广泛.它的最大特点,在于它的后进先出特性,因此栈通常也被叫做'LIFO'表.栈的实现有两种,可以用链表,也可以用数组,两种方法我都会写,但我更倾向于选择链表这种实现方式,不仅节约空间,而且使用起来比较灵活.

    相较于普通的链表,栈无疑具有一些特殊的操作,主要是两个:

    进栈(Push)

    出栈(Pop)

    所谓Push就是把元素压入到栈的顶端,Pop操作就是把栈顶的元素取出来,并返回.

    链表实现

    Stack.h

    #ifndef STACK_H
    #define STACK_H
    
    #include <iostream>
    using namespace std;
    
    struct StackNode;
    typedef struct StackNode *PtrToNode;
    typedef PtrToNode Stack;
    typedef int ElementType;
    
    int IsEmpty(Stack S);
    Stack CreateStack();
    void MakeEmpty(Stack S);
    void Push(ElementType X, Stack S);
    ElementType Top(Stack S);
    ElementType Pop(Stack S);
    void DisposeStack(Stack S);
    void Print(Stack S);
    
    struct StackNode{
        ElementType Element;
        PtrToNode Next;
    };
    
    int IsEmpty(Stack S){
        return S->Next == nullptr;
    }
    
    Stack CreateStack(){
        Stack S = new StackNode;
        S->Next = nullptr;
        return S;
    }
    
    void MakeEmpty(Stack S){
        if(S == nullptr){
            return;
        }else{
            while(!IsEmpty(S)){
                Pop(S);
            }
        }
    }
    
    void Push(ElementType X, Stack S){
        PtrToNode tmpCell = new StackNode;
    
        tmpCell->Element = X;
        tmpCell->Next = S->Next;
        S->Next = tmpCell;
    }
    
    ElementType Top(Stack S){
        if(!IsEmpty(S)){
            return S->Next->Element;
        }
        return -1;
    }
    
    ElementType Pop(Stack S){
        if(!IsEmpty(S)){
            ElementType tmp;
            PtrToNode firstCell = S->Next;
            tmp = firstCell->Element;
            S->Next = firstCell->Next;
            delete firstCell;
            return tmp;
        }
        return -1;
    }
    
    void DisposeStack(Stack S){
        PtrToNode P = S->Next, tmp;
        S->Next = nullptr;
        while(P != nullptr){
            tmp = P->Next;
            delete P;
            P = tmp;
        }
    }
    
    void Print(Stack S){
        PtrToNode P = S->Next;
        while(P != nullptr){
            cout << P->Element << "->";
            P = P->Next;
        }
        cout << "nullptr" << endl;
    }
    #endif // STACK_H
    

    这里我依旧添加了一个Print()的函数,方便测试.

    数组实现

    StackArray.h

    #ifndef STACKARRAY_H
    #define STACKARRAY_H
    
    #include <iostream>
    
    using namespace std;
    
    typedef int ElementType;
    struct StackRecord;
    typedef struct StackRecord *Stack;
    
    int IsEmpty(Stack S);
    int IsFull(Stack S);
    Stack CreateStack(int MaxElements);
    void DisposeStack(Stack S);
    void MakeEmpty(Stack S);
    void Push(ElementType X, Stack S);
    ElementType Top(Stack S);
    ElementType Pop(Stack S);
    void Print(Stack S);
    
    struct StackRecord{
        int Capacity;
        int TopOfStack;
        ElementType *Array;
    };
    
    int IsEmpty(Stack S){
        return S->TopOfStack == -1;
    }
    
    int IsFull(Stack S){
        return S->TopOfStack == S->Capacity - 1;
    }
    
    Stack CreateStack(int MaxElements){
        Stack S = new StackRecord;
    
        S->Capacity = MaxElements;
        S->Array = new ElementType[MaxElements];
        MakeEmpty(S);
    
        return S;
    }
    
    void DisposeStack(Stack S){
        delete S->Array;
        delete S;
    }
    
    void MakeEmpty(Stack S){
        S->TopOfStack = -1;
    }
    
    void Push(ElementType X, Stack S){
        if(IsFull(S)){
            return;
        }else{
            S->Array[++S->TopOfStack] = X;
        }
    }
    
    ElementType Top(Stack S){
        if(IsEmpty(S)){
            return -1;
        }else{
            return S->Array[S->TopOfStack];
        }
    }
    
    ElementType Pop(Stack S){
        if(IsEmpty(S)){
            return -1;
        }else{
            return S->Array[S->TopOfStack--];
        }
    }
    
    void Print(Stack S){
        if(!IsEmpty(S)){
            for(int i = 0; i <= S->TopOfStack; ++i){
                cout << S->Array[i] << "->";
            }
        }
        cout << endl;
    }
    
    
    #endif // STACKARRAY_H
    
    

    3.队列

    与栈有所不同,队列是一种"先进先出"的数据结构,可以理解为排队:谁先到.就先为谁服务.队列会有一些跟高级的用法,这些后面才会涉及到,这里我们仅仅实现最基础的部分,同样可以分两种形式实现:数组和链表,具体应用中如何使用因人而异,如果数据量不是特别大的话,用数组实现也许会更加清楚直接一些.
    ADT这种形式对于数据结构的封装,无疑减轻了我们调用时的难度.

    QueueArray.h

    #ifndef QUEUEARRAY_H
    #define QUEUEARRAY_H
    
    #include <iostream>
    
    using namespace std;
    
    typedef int ElementType;
    struct QueueRecord;
    typedef struct QueueRecord *Queue;
    
    int IsEmpty(Queue Q);
    int IsFull(Queue Q);
    Queue CreateQueue(int MaxElements);
    void DisposeQueue(Queue Q);
    void MakeEmpty(Queue Q);
    ElementType Dequeue(Queue Q);
    ElementType Front(Queue Q);
    void Enqueue(ElementType X, Queue Q);
    static int Succ(int Value, Queue Q);
    void Print(Queue Q);
    
    struct QueueRecord{
        int Capacity;
        int Front;
        int Rear;
        int Size;
        ElementType *Array;
    };
    
    int IsEmpty(Queue Q){
        return Q->Size == 0;
    }
    
    int IsFull(Queue Q){
        return Q->Size == Q->Capacity;
    }
    
    Queue CreateQueue(int MaxElements){
        Queue Q = new QueueRecord;
    
        Q->Capacity = MaxElements;
        Q->Array = new ElementType[MaxElements];
        MakeEmpty(Q);
    
        return Q;
    }
    
    void MakeEmpty(Queue Q){
        Q->Size = 0;
        Q->Front = 0;
        Q->Rear = -1;
    }
    
    static int Succ(int Value, Queue Q){
        if(++Value == Q->Capacity){
            Value = 0;
        }
        return Value;
    }
    
    void Enqueue(ElementType X, Queue Q){
        if(IsFull(Q)){
            return;
        }else{
            Q->Rear = Succ(Q->Rear, Q);
            Q->Array[Q->Rear] = X;
            ++Q->Size;
        }
    }
    
    ElementType Dequeue(Queue Q){
        ElementType temp;
    
        if(IsEmpty(Q)){
            return -1;
        }else{
            temp = Q->Array[Q->Front];
            Q->Front = Succ(Q->Front, Q);
            --Q->Size;
        }
        return temp;
    }
    
    ElementType Front(Queue Q){
        if(IsEmpty(Q)){
            return -1;
        }else{
            return Q->Array[Q->Front];
        }
    }
    
    void DisposeQueue(Queue Q){
        delete Q->Array;
        delete Q;
    }
    
    void Print(Queue Q){
        int i, j = Q->Front;
        for(i = 0; i < Q->Size; ++i){
            cout << Q->Array[j] << "->";
            j = Succ(j, Q);
        }
        cout << endl;
    }
    
    #endif // QUEUEARRAY_H
    
    

    Queue.h

    #ifndef QUEUE_H
    #define QUEUE_H
    
    #include <iostream>
    
    using namespace std;
    
    typedef int ElementType;
    struct QueueNode;
    typedef struct QueueNode *PtrToNode;
    typedef PtrToNode Queue;
    typedef PtrToNode Position;
    
    int IsEmpty(Queue Q);
    Queue CreateQueue();
    void DisposeQueue(Queue Q);
    void MakeEmpty(Queue Q);
    ElementType Dequeue(Queue Q);
    ElementType Front(Queue Q);
    void Enqueue(ElementType X, Queue Q);
    void Print(Queue Q);
    
    struct QueueNode{
        ElementType Element;
        Position Next;
    };
    
    int IsEmpty(Queue Q){
        return Q->Next == nullptr;
    }
    
    Queue CreateQueue(){
        Queue Q = new QueueNode;
        Q->Next = nullptr;
        return Q;
    }
    
    void Enqueue(ElementType X, Queue Q){
        Position P = Q, tmpCell;
        while(P->Next != nullptr){
            P = P->Next;
        }
        tmpCell = new QueueNode;
        tmpCell->Element = X;
        tmpCell->Next = P->Next;
        P->Next = tmpCell;
    }
    
    ElementType Dequeue(Queue Q){
        if(IsEmpty(Q)){
            return -1;
        }else{
            Position P = Q->Next;
            ElementType temp;
            temp = P->Element;
            Q->Next = P->Next;
            delete P;
            return temp;
        }
    }
    
    ElementType Front(Queue Q){
        if(IsEmpty(Q)){
            return -1;
        }else{
            return Q->Next->Element;
        }
    }
    
    void DisposeQueue(Queue Q){
        Position P = Q->Next, tmpCell;
        Q->Next = nullptr;
        while(P != nullptr){
            tmpCell = P->Next;
            delete P;
            P = tmpCell;
        }
    }
    
    void Print(Queue Q){
        Position P = Q->Next;
        while(P != nullptr){
            cout << P->Element << "->";
            P = P->Next;
        }
        cout << endl;
    }
    
    #endif // QUEUE_H
    
    

    总结:三种数据结构:链表,栈,队列三种数据结构的实现均已完成.这三种数据结构或许在计算机科学中是最基本的三种数据机构了,应用广泛,栈可用来记录过程和函数调用,以及递归的实现,队列可用以处理计算机网络的访问分配,等等.下一节我们会接触到树这种更为复杂,也更为有意思的数据结构.

    却道,此心安处是吾乡
  • 相关阅读:
    git cmd 命令在已有的仓库重新添加新的文件夹
    google guava Multimap的学习介绍
    JavaScript笔记基础版
    初识hive
    深入学习HBase架构原理
    初识Azkaban
    MapReduce工作流多种实现方式
    Hive 分组问题
    sqoop使用中的小问题
    Sqoop 结合多种系统的具体应用
  • 原文地址:https://www.cnblogs.com/lucifer25/p/7879877.html
Copyright © 2011-2022 走看看