序言

本文记录学习的经典数据结构的实现, 由于原严蔚敏的书中使用的代码为C with &, 因此在真正的实现上是需要依赖于 cpp 的, 因此本文在具体的实现上为了能够"真正使用"有一些细节上的改动.

在本文中的 ElemType 使用以下语句定义:

#ifndef ElemType
#define ElemType int
#endif

List

Static Sequence List

#define MaxSize 50
//数据类型为ElemType, 长度为 MaxSize 的静态线性表
typedef struct{
    ElemType data[MaxSize];
    int length;//表长
}SqList

int main(){

}

Dynamic Sequence List

Definition

#define InitSize 100

typedef struct{
    ElemType *data; //表的地址
    int MaxSize;    //动态表的最大长度
    int length;     //当前动态表的长度
}SeqList;

int main(){
    SeqList L;
    L.data = (ElemType *)malloc(sizeof(ElemType) * InitSize);   //动态分配
    //
    free(L);
    return 0;
}

Operations

//初始化动态表L
bool InitList(SeqList &L){
    L.data = (ElemType *)malloc(sizeof(ElemType) * InitSize);
    if(L.data == NULL){//分配内存失败
        return false;
    }
    L.length = 0;
    return true;
}
//在静态顺序表L中的第 i 位插入元素 e
bool ListInsert(SqList &L, int i, ElemType e){
    if(i < 1 || i > L.length + 1){  //判断传入的参数 i 是否合法
        return false;
    }
    if(L.length >= MaxSize){ //判断静态表是否已满
        return false;
    }
    for(int j = L.length; j >= i; j--){
        L.data[j] = L.data[j - 1]; //依次后移
    }
    L.data[i - 1] = e;
    L.length++;
    return true;
}

//删除静态顺序表 L 中的第 i 位元素, 并且通过传入参数 e 保存删除的元素
bool ListDelete(SqList &L, int i, ElemType &e){
    if(i < 1 || i > L.length){  //判断传入的参数 i 是否合法
        return false;
    }
    for(int j = i; j < L.lrngth; j++){
        L.data[j - 1] = L.data[j];//依次前移
    }
    L.length--;
    return true;
}

//在静态顺序表 L 中查找第一个值为 e 的元素的[位置]
bool LocateElem(SqList &L, int i, ElemType e){
    int i;
    for(i = 0; i < L.length; i++){
        if(L.data[i] == e){
            return i + 1;//查找的是位置, 因此数组下标需要+1转换为编号
        }
    }
    return 0;//查找失败
}

Linked List

Definition

//单链表
typedef struct ListNode{
    ElemType data;          //数据域
    struct ListNode *next;  //下一结点地址
}ListNode, *LinkList;

Operations

//头插法建立单链表 L
LinkList List_HeadInsert(LinkList &L){
    ListNode *s;
    int x;
    L = (LinkList)malloc(sizeof(ListNode));
    L -> next = NULL;
    scanf("%d", &x);
    while(x != 9999){   //输入9999即代表结束插入
        s = (ListNode *)malloc(sizeof(ListNode));
        s -> data = x;
        s -> next = L -> next;
        L -> next = s;
        scanf("%d", &x);
    }
    return L;
}

//尾插法建立单链表 L
LinkList List_TailInsert(LinkList &L){
    int x;//接收键盘输入的数值
    L = (LinkList)malloc(sizeof(ListNode));
    ListNode *new_node, *tail = L;    //tail 为表尾指针
    scanf("%d", &x);
    while(x != 9999){       //输入9999即代表结束插入
        new_node = (ListNode *)malloc(sizeof(ListNode));
        new_node -> data = x;
        tail -> next = new_node;
        tail = new_node;
        scanf("%d", &x);
    }
    tail -> next = NULL;    //将尾指针置空
    return L;
}

//在单链表 L 中按照序号查找结点
ListNode *GetElem(LinkList L, int i){
    if(i < 1){//检查传入的参数 i 是否合法
        return NULL;
    }
    int j = 1;
    ListNode *ptr = L -> next;
    while(ptr != NULL && j < i){
        ptr = ptr -> next;
        j++;
    }
    return ptr;
}

//在单链表 L 中按照值查找结点
ListNode *LocateElem(LinkList L, ElemType e){
    ListNode *ptr = L -> next;
    while(ptr != NULL && ptr -> data != e){
        ptr = ptr -> next;
    }
    return ptr;
}

Stack(template)

template<typename T, int Size>//模板类, 传入参数栈元素的数据类型 T, 和栈的最大深度 Size
class Stack{
private:
    T data[size];
    int top;    //当前栈中的栈顶元素的数组下标
public:
    Stack():top(-1){
        //初始化函数
    }

    ~Stack(){
        //析构函数
    }

    //向栈进入元素 item
    bool push(T item){
        if(top == Size - 1){    //检测栈是否已满
            return false;
        }
        data[++top] = item;
        return true;
    }

    //出栈栈顶元素, 并且使用 topElem 记录这个元素
    bool pop(T &topElem){
        if(top == -1){  //检验栈是否为空
            return false;
        }
        topElem = data[top];
        return true;
    }

    //判断栈是否为空
    bool isEmpty(){
        return top == -1;
    }

    //判断栈是否已满
    bool isFull(){
        return top == Size - 1;
    }
}

Queue(Template)

template<typename T, int Size>//模板类, 传入参数队列元素的数据类型 T, 和队列的最大长度 Size
class Queue{
private:
    T data[Size];
    int front;  //队头元素数组下标
    int rear;   //队尾元素数组下标
    int tag;    //辅助变量, 判断队列为空/满
public:
    Queue(): front(0), rear(0), tag(0){
        //构造函数
    }

    ~Queue(){
        //析构函数
    }

    //元素 item 入队
    bool EnQueue(T, item){
        if(front == rear && tag == 1){  //判断队列是否已满
            return false;
        }
        rear = (rear + 1) % Size;
        data[rear] = item;
        tag = 1;    //进行入队操作后, 将tag = 1, 这样 rear == front时只有可能为满
        return true;
    }

    //队列出队, 并且记录出队元素 item
    bool DeQueue(T &item){
        if(front == rear && tag == 0){  //判断队列是否为空
            return false;
        }
        rear = (rear + 1) % Size;
        tag[rear] = item;
        tag = 0;    //进行出队操作后, 将tag = 0, 这样 rear == front时只有可能为空
        return true;
    }

    //判断队列是否为空
    bool isEmpty(){
        return front == rear && tag == 0;
    }

    //判断队列是否为满
    bool isFull(){
        return front == rear && tag == 1;
    }
}

String

Definition

Static String

static const int MAXLEN = 255;//字符串的最大长度

//静态分配字符串
typedef struct{
    char ch[MAXLEN];//数据域
    int length;     //字符串长度
}SString

Dynamic String

//动态分配字符串
typedef struct{
    char *ch;       //字符数组的地址
    int length;     //字符串长度
}HString;

Linked List String

//使用字符串结点存储字符串
typedef struct StringNode{
    char ch[4]; //4个字符一组存放在一个结点中
    struct StringNode *next;    //下一个字符结点的地址
}StringNode, *String;

Operations

Static String

//求静态字符串 S 中, 以 pos 为起点, 长为 len 的子串 sub.
//在这里, 我们设定字符串的S[0]不存储任何元素, 而是从S[1]开始存储字符串的元素
bool SubString(SString &sub, SString S, int pos, int len){
    if(pos + len - 1 > S.length){   //检测子串末尾是否已经溢出原串长度
        return false;
    }
    for(int i = pos; i < pos + len; i++){
        sub.ch[i - pos + 1] = S.ch[i];
        
    }
}

//比较两个静态串的大小
//串的大小定义:(1)首先比长度(2)长度相等时, 比char对应的int.
bool StrCompare(SString S, SString, T){
    for(int i = 1; i <= S.length && i <= T.length; i++){
        if(S.ch[i] != T.ch[i]){
            return S.ch[i] - T.ch[i];
        }
    }
    //未能在以上循环中完成输出, 说明两个串呈现包含关系(即S 是 T的子串, 或者相反)
    //那么就应该使用长度来比较
    return S.length - T.length;
}

//查询静态串的长度
int StrLength(SStrng S){
    return S.length;
}

//使用朴素便利方法查询子串 T 首次出现在 S 中时的位置
int Index(SString S, SString T){
    int i = 1, j = 1;
    while(i <= S.length && j <= T.length){
        if(S.ch[i] == T.ch[i]){
            //匹配成功, i,j同步后移以进行下一位的比较
        }
        else{
            //匹配失败, 则 i 回到原先起点的下一位开始重新匹配
            i = i - j + 2;
            j = 1;
        }
    }
    if(j > T.length){
        return i - T.length;
    }
    else{
        return 0;
    }
}

//使用KMP算法, 借助next[]数组查询子串 T 首次出现在 S 中时的位置
int Index_KMP(SString S, SString T, int next[]){
    int i = 1, j = 1;
    while(i <= S.length && j <= T.length){
        if(j == 0 || S.ch[i] = = T.ch[j]){
            i++;
            j++;
        }
        else{
            j = next[j];
        }
    }
    if(j > T.length){
        return i - T.length;
    }
    else{
        return 0;
    }
}

//根据next[]数组生成nextval[]数组, 从而优化KMP算法
int *next2nextval(SString T, int next[]){
    int *nextval = (int *)malloc(T.length * sizeof(char));
    nextval[1] = 0;
    for(int j = 2; j <= T.length; j++){
        if(T.ch[next[j]] == T.ch[j]){
            nextval[j] = nextval[next[j]];
        }
        else{
            nextval[j] = next[j];
        }
    }
    return nextval;
}

Dynamic String

//初始化动态字符串
bool InitHString(HString &S){
    S.ch = (char *)malloc(MAXLEN * sizeof(char));
    if(S.ch == NULL){   //内存分配失败
        return false;
    }
    S.length = 0;
    return true;
}

Tree & Binary Tree

Binary Tree

Definition

#define MAXSIZE 10

//二叉树结点
typedef struct BiTNode{
    ElemType data;          //数据域
    struct BiTNode *lchild; //左子树根结点地址
    struct BiTNode *rchild; //右子树根结点地址
}BiTNode, *BiTree;

Operations

//初始化二叉树root
void InitBiTree(BiTree &root){
    root = NULL;//通过置空来清洗之间root所在空间中地址
    root = (BiTree)malloc(sizeof(BiTNode));
    root -> data = 1;
    root -> lchild = NULL;
    root -> rchild = NULL;
}

//向二叉树root中插入值为 val 的结点
bool InsertBiTNode(BiTree &root, ElemType val){
    BiTNode *new_node = (BiTNode *)malloc(sizeof(BiTNode));
    if(new_node == NULL){
        return false;
    }
    if(root -> lchild == NULL){
        root -> lchild = new_node;
        new_node -> data = val;
        new_node -> lchild = NULL;
        new_node -> rchild = NULL;
    }
    else if(root -> rchild == NULL){
        root -> rchild = new_node;
        new_node -> data = val;
        new_node -> lchild = NULL;
        new_node -> rchild = NULL;
    }
    else{
        std::cout << "Invalid root!" << std::endl;
        return false;
    }
}

//定义方位二叉树结点的行为
void observe(BiTree T){
    std::cout << T -> data << std::endl;
}

//前根遍历二叉树 T
//使用递归定义
void PreOrder(BiTree T){
    if(T != NULL){
        observe(T);
        PreOrder(T -> lchild);
        PreOrder(T -> rchild);
    }
}

//中根遍历二叉树 T
//使用递归定义
void InOrder(BiTree T){
    if(T != NULL){
        InOrder(T -> lchild);
        observe(T);
        InOrder(T -> rchild);
    }
}

//后根遍历二叉树 T
//使用递归定义
void PostOrder(BiTree T){
    if(T != NULL){
        PostOrder(T -> lchild);
        PostOrder(T -> rchild);
        observer(T);
    }
}

//层次遍历二叉树 T
//借助队列模板类实现
void LevelOrder(BiTree T){
    Queue<BiTree,20>queue;
    BiTree p = NULL;
    queue.Enqueue(T);

    while(!queue.isEmpty()){
        queue.DeQueue(p);
        observe(p);
        if(p -> lchild != NULL){
            queue.EnQueue(p -> lchild);
        }
        if(p -> rchild != NULL){
            queue.EnQueue(p -> rchild);
        }
    }
}

Thread Tree

Definition

typedef struct ThreadNode{
    ElemType data;              //数据域
    struct ThreadNode *lchild;  //左子树的根结点地址
    struct ThreadNode *rchild;  //右子树的根结点地址
    int ltag;                   //标记左子树根结点是否为线索, 1 为 是, 0 为 非
    int rtag;                   //标记右子树根结点是否为线索, 1 为 是, 0 为 非
}

Operation

//使用全局变量 pre 来指定前驱结点
ThreadNode *pre = NULL;

//访问行为 visit()
void visit(ThreadNode *nodeptr){
    //没有左孩子, 则空链域可以用来存储前驱结点地址
    if(nodeptr -> lchild == NULL){
        nodeptr -> lchild = pre;
        nodeptr -> ltag = 1;
    }

    //没有右孩子, 则空链域可以用来存储后继结点地址
    if(pre != NULL && pre -> rchild == NULL){
        pre -> rchild = nodeptr;
        pre -> rtag = 1;
    }

    pre = nodeptr;
}