数据结构与算法

数据结构

1.顺序表

顺序表是在计算机内存中以数组的形式保存的线性表。(存储单元地址连续)

template <class T>
class SortList
{
private:
    T data[Masize]; //最大容量为MaxSize
    int length;

public:
    SortList();
    ~SortList();
    void Insert(T x); //有序插入(从小到大)
    int Locate(T x);  //查找
    void Display();   //输出表中信息
}; 
template <class T>
SortList<T>::SortList()
{
    for (int i = 0; i < MaxSize; i++)
    {
        data[i] = 0;
    }
    length = 0;
}
template <class T>
SortList<T>::~SortList()
{
}
template <class T>
void SortList<T>::Insert(T x)
{
    if (length >= Maxsize)
        throw "Overflow";
    int pos;
    for (pos = 0; pos < length; pos++)
    {
        if (x < data[pos])
            break;
    }
    for (int i = length; i >= pos; i--)
    {
        data[i + 1] = data[i];
    }
    data[pos] = x;
    lenght++;
}
template <class T>
int SortList<T>::Locate(T x)
{
    int ret = -1;
    for (int i = 0; i < length; i++)
    {
        if (data[i] == x)
            ret = i;
        else if (data[i] > x) //后续不可能存在比当前位置小的数据
            break;
    }
    if (ret == -1)
        throw "No found";
    else
        return ret;
}
template <class T>
void SortList<T>::Display()
{
    for (int i = 0; i < length; i++)
    {
        cout << data[i] << " ";
    }
    cout << endl;
}

2.链表

链表是一种物理存储单元上非连续、非顺序的存储结构,由一个一个的节点连接而成。

链表根据节点的不同分成单向、单向循环、双向循环链表。

//双向循环链表
template <class T>
struct Node//节点
{
    T data;//数据域
    Node<T> *prior, *next;//指针域(分别有前指针prior和后指针next)
};

template <class T>
class LinkList
{
public:
    LinkList();      //建立只有头结点的双向循环链表链表
    ~LinkList();     //析构函数
    int Length();     //求链表的长度
    void Insert(T x); //表尾插入x
    void DispListF(); //正向遍历链表,按照逻辑序号输出各元素
    void DispListR(); //反向遍历链表,按照反向逻辑序号输出各元素
private:
    Node<T> *first; //链表的头指针
};
template <class T>
LinkList<T>::LinkList()
{
    first = new Node<T>;
    first->next = first->prior = first;
}
template <class T>
LinkList<T>::~LinkList()
{
    Node<T> *s;
    s = first->next;
    while (s != first)
    {
        first->next = s->next;
        delete s;
        s = first->next;
    }
    delete s;
}
template <class T>
int LinkList<T>::Length()
{
    Node<T> *p;
    int length=0;
    p = first;
    while (p->next != first)
    {
        length++;
        p = p->next;
    }
    return length;
}
template <class T>
void LinkList<T>::Insert(T x)
{
    Node<T> *p;
    p=new Node<T>;
    p->data=x;
    p->prior=first->prior;
    p->prior->next=p;
    p->next=first;
    first->prior=p;
}
template <class T>
void LinkList<T>::DispListF()
{
    cout<<"The length:"<<Length()<<endl;
    cout<<"The elements:";
    Node<T> *p;
    p=first;
    while (p->next!=first)
    {
        p=p->next;
        cout<<p->data<<" ";
    }
    cout<<endl;
}
template <class T>
void LinkList<T>::DispListR()
{
    cout<<"The length:"<<Length()<<endl;
    cout<<"The elements:";
    Node<T> *p;
    p=first;
    while (p->prior!=first)
    {
        p=p->prior;
        cout<<p->data<<" ";
    }
    cout<<endl;
}

典型例题:约瑟夫问题。

3.栈

栈是一种运算受限的线性表,限定仅在表尾进行插入和删除操作的线性表。

//链式栈
template <class T>
class Node
{
public:
    T data;
    Node<T> *prior;
};
template <class T>
class LinkStack
{
public:
    LinkStack();    //构造函数,置空链栈
    ~LinkStack();   //析构函数,释放链栈中各结点的存储空间
    void Push(T x); //将元素x入栈
    T Pop();        //将栈顶元素出栈
    T GetTop();     //取栈顶元素(并不删除)
    bool Empty();   //判断链栈是否为空栈
private:
    Node<T> *top; //栈顶指针即链栈的头指针
};
template <class T>
LinkStack<T>::LinkStack()
{
    top = NULL;
}
template <class T>
LinkStack<T>::~LinkStack()
{
    Node<T> *p, *s;
    p = top;
    while (p != NULL)
    {
        s = p;
        p = p->prior;
        delete s;
    }
    top = NULL;
}
template <class T>
void LinkStack<T>::Push(T x)
{
    Node<T> *p, *s;
    p = top;
    s = new Node<T>;
    s->data = x;
    s->prior = p;
    top = s;
}
template <class T>
T LinkStack<T>::Pop()
{
    Node<T> *p;
    p = top;
    top = top->prior;
    T s = p->data;
    delete p;
    return s;
}
template <class T>
T LinkStack<T>::GetTop()
{
    if (top != NULL)
        return top->data;
    else
        throw "Downflow";
}
template <class T>
bool LinkStack<T>::Empty()
{
    if (top == NULL)
        return true;
    return false;
}

典型例题:进制转换、逆波兰式。

4.队列

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。

//循环队列
class CirQueue
{
public:
    CirQueue();        //构造函数,置空队
    ~CirQueue();       //析构函数
    void EnQueue(T x); //将元素x入队
    T DeQueue();       //将队头元素出队
    T GetQueue();      //取队头元素(并不删除)
    bool Empty();      //判断队列是否为空
    bool Full();       //判断队列是否为满
private:
    T data[QueueSize]; //存放队列元素的数组
    int front, rear;   //队头和队尾指针,分别指向队头元素所在数组的前一下标和队尾元素的数组下标
    int count;         //记录队列中数据个数
};
template <class T>
CirQueue<T>::CirQueue()
{
    front = rear = QueueSize - 1;
    count = 0;
}
template <class T>
CirQueue<T>::~CirQueue()
{
}
template <class T>
T CirQueue<T>::DeQueue()
{
    if (Empty())
        throw "Downflow";
    count--;
    int tmp = front;
    front = (front + 1) % QueueSize; //队头指针在循环意义下加1
    return data[tmp];                //读取并返回出队前的队头元素,注意队头指针
}
template <class T>
T CirQueue<T>::GetQueue()
{
    int i;
    if (Empty())
        throw "Downflow";
    i = (front + 1) % QueueSize; //注意不要给队头指针赋值
    return data[i];
}
template <class T>
bool CirQueue<T>::Empty()
{
    if (count == 0)
        return true;
    return false;
}
template <class T>
bool CirQueue<T>::Full()
{
    if (count == 5)
        return true;
    return false;
}
template <class T>
void CirQueue<T>::EnQueue(T x)
{
    if (!Full())
    {
        count++;
        data[rear] = x;
        rear = (rear + 1) % QueueSize;
    }
    else
        throw "Overflow";
}

5.二叉树

二叉树是树形结构的一个重要类型,二叉树特点是每个结点最多只能有两棵子树,且有左右之分。

先序遍历(递归):先访问根节点,然后访问左节点,最后访问右节点。

中序遍历(递归):先访问左节点,然后访问根节点,最后访问右节点。

后序遍历(递归):先访问左节点,然后访问右节点,最后访问根节点。

非递归遍历:利用栈消除递归。

层次遍历:利用队列遍历。

计算叶子节点:递归统计左右子叶的和。

计算高度:递归比较左右子叶高度。

5.1数组实现

template <class T>
class BiTree
{
public:
    BiTree(T *);             //构造函数,初始化一棵二叉树,其前序序列由键盘输入
    void PreOrder(int pos);  //前序遍历二叉树
    void InOrder(int pos);   //中序遍历二叉树
    void PostOrder(int pos); //后序遍历二叉树
    int CountLeaf(int pos);  //计算叶子结点总数
    int Depth(int pos);      //计算高度
    void PreOrder();         //非递归先序遍历
    void LevelOrder();       //层次遍历
private:
    T data[TreeSize];
    //存储结点的元素值,根结点存储在1下标,双亲下标为i,则左右孩子依次为2i,2i+1
};

//constructor
template <class T>
BiTree<T>::BiTree(T *str)
{
    strcpy(data + 1, str);
}
template <class T>
void BiTree<T>::PreOrder(int pos)
{
    if (data[pos] != '#')
    {
        cout << data[pos] << " "; //根
        PreOrder(pos * 2);        //左
        PreOrder(pos * 2 + 1);    //右
    }
} //前序遍历二叉树
template <class T>
void BiTree<T>::InOrder(int pos)
{
    if (data[pos] != '#')
    {
        InOrder(pos * 2);         //左
        cout << data[pos] << " "; //根
        InOrder(pos * 2 + 1);     //右
    }
} //中序遍历二叉树
template <class T>
void BiTree<T>::PostOrder(int pos)
{
    if (data[pos] != '#')
    {
        PostOrder(pos * 2);       //左
        PostOrder(pos * 2 + 1);   //右
        cout << data[pos] << " "; //根
    }
} //后序遍历二叉树
template <class T>
int BiTree<T>::CountLeaf(int pos)
{
    if (data[pos] == '#')
    {
        return 0;
    }
    if (data[pos * 2] == '#' && data[pos * 2 + 1] == '#')
    {
        return 1;
    }
    return CountLeaf(pos * 2) + CountLeaf(pos * 2 + 1); //递归
} //计算叶子结点总数
template <class T>
int BiTree<T>::Depth(int pos)
{
    if (data[pos] == '#')
    {
        return 0;
    }
    return max(Depth(pos * 2), Depth(pos * 2 + 1)) + 1; //比较高度

} //计算高度
template <class T>
void BiTree<T>::PreOrder()
{
    stack<int> stack;
    stack.push(1);
    while (!stack.empty())
    {
        int top = stack.top();
        stack.pop();
        cout << data[top] << " "; //根
        if (data[top * 2 + 1] != '#')
        {
            stack.push(top * 2 + 1); //右
        }
        if (data[top * 2] != '#')
        {
            stack.push(top * 2); //左
        }
    }
} //非递归先序遍历
template <class T>
void BiTree<T>::LevelOrder()
{
    queue<int> queue;
    queue.push(1);
    while (!queue.empty())
    {
        int front = queue.front();
        queue.pop();
        cout << data[front] << " "; //根
        if (data[front * 2] != '#')
        {
            queue.push(front * 2); //左
        }
        if (data[front * 2 + 1] != '#')
        {
            queue.push(front * 2 + 1); //右
        }
    }
} //层次遍历

5.2节点实现

template <class T>
struct BiNode //二叉树的结点结构
{
    T data;
    BiNode<T> *lchild, *rchild;
};
template <class T>
class BiTree
{
public:
    BiTree();             //构造函数,初始化一棵二叉树,其前序序列由键盘输入
    ~BiTree();            //析构函数,释放二叉链表中各结点的存储空间
    void PreOrder(BiNode<T> *bt);  //前序遍历二叉树
    void InOrder(BiNode<T> *bt);   //中序遍历二叉树
    void PostOrder(BiNode<T> *bt); //后序遍历二叉树
    int CountLeaf(BiNode<T> *a); //递归方法计算叶子数
    int Depth(BiNode<T> *a);     //递归方法计算高度
    void PreOrder(void);   //先序非递归
    void LevelOrder(void); //层次遍历
    void change(BiNode<T> *bt);   //交换左右子树
    BiNode<T> *SearchBST(BiNode<T> *bt, T key); //查找值为k的结点,返回值为k所在结点的地址

private:
    BiNode<T> *root;               //指向根结点的头指针
    void Creat(BiNode<T> *&bt);    //被构造函数调用,递归方式生成二叉树
    void Release(BiNode<T> *&bt);  //被析构函数调用
    
};
//构造函数:Creat利用创建二叉树
template <class T>
BiTree<T>::BiTree()
{
    Creat(root);
}
//功    能:递归方法创建一棵二叉树,由构造函数调用
template <class T>
void BiTree<T>::Creat(BiNode<T> *&bt)
{
    T ch;
    cin >> ch;
    if (ch == "#")
        bt = nullptr; //创建结点值为字符串的二叉树
    else
    {
        bt = new BiNode<T>; //生成一个结点
        bt->data = ch;
        Creat(bt->lchild); //递归建立左子树
        Creat(bt->rchild); //递归建立右子树
    }
}
//功    能:析构函数,释放二叉链表中各结点的存储空间
template <class T>
BiTree<T>::~BiTree() //析构函数不能带参数
{
    Release(root);
}
//功    能:释放二叉树的存储空间,析构函数调用
template <class T>
void BiTree<T>::Release(BiNode<T> *&bt)
{
    if (bt != nullptr)
    {
        Release(bt->lchild); //释放左子树
        Release(bt->rchild); //释放右子树
        delete bt;
    }
}
template <class T>
void BiTree<T>::PreOrder(BiNode<T> *bt)
{
    if (bt != nullptr)
    {
        cout << bt->data << " ";
        PreOrder(bt->lchild);
        PreOrder(bt->rchild);
    }
    else
    {
        return;
    }
} //前序遍历二叉树
template <class T>
void BiTree<T>::InOrder(BiNode<T> *bt)
{
    if (bt != nullptr)
    {
        InOrder(bt->lchild);
        cout << bt->data << " ";
        InOrder(bt->rchild);
    }
    else
    {
        return;
    }
} //中序遍历二叉树
template <class T>
void BiTree<T>::PostOrder(BiNode<T> *bt)
{
    if (bt != nullptr)
    {
        PostOrder(bt->lchild);
        PostOrder(bt->rchild);
        cout << bt->data << " ";
    }
    else
    {
        return;
    }
} //后序遍历二叉树
template <class T>
int BiTree<Te>::CountLeaf(BiNode<DataType> *a)
{
    if(a==nullptr)
    {
        return 0;
    }
    if(a->lchild==nullptr&&a->rchild==nullptr)
    {
        return 1;
    }
    return CountLeaf(a->lchild)+CountLeaf(a->rchild);
} //递归算法计算叶子数
template <class T>
int BiTree<T>::Depth(BiNode<T> *a)
{
    if(a==nullptr)
    {
        return 0;
    }
    return max(Depth(a->lchild), Depth(a->rchild)) + 1;
} //递归算法计算高度
template <class T>
void BiTree<T>::PreOrder(void)
{
    stack<BiNode<T>*> stack;
    stack.push(root);
    while (!stack.empty())
    {
        BiNode<T> *top= stack.top();
        stack.pop();
        cout << top->data << " "; //根
        if (top->rchild!=nullptr)
        {
            stack.push(top->rchild); //右
        }
        if (top->lchild!=nullptr)
        {
            stack.push(top->lchild); //左
        }
    }
} //先序非递归
template <class T>
void BiTree<T>::LevelOrder(void)
{
    queue<BiNode<T>*> queue;
    queue.push(root);
    while (!queue.empty())
    {
        BiNode<T> * front = queue.top();
        queue.pop();
        cout << front->data << " "; //根
        if (front->lchild!=nullptr)
        {
            queue.push(front->lchild); //左
        }
        if (front->rchild!=nullptr)
        {
            queue.push(front->rchild); //右
        }
    }
} //层次遍历
template <class T>
void BiTree<T>::change(BiNode<T> *bt)
{
    if (bt != nullptr)
    {
        BiNode<T> *tmp;
        tmp=bt->lchild ;
        bt->lchild = bt->rchild;
        bt->rchild = tmp;
        change(bt->lchild);
        change(bt->rchild);
    }
    else
    {
        return;
    }
} //交换左右子树
template <class T>
BiNode<T> *BiSortTree<T>::SearchBST(BiNode<T> *bt, T key)
{
    if (bt == nullptr)
    {
        return nullptr;
    }
    else if (bt->data == key)
    {
        return bt;
    }
    else if (bt->data < key)
    {
        if (bt->rchild == nullptr)
            return nullptr;
        else
            return SearchBST(bt->rchild, key);
    }
    else if (bt->data > key)
    {
        if (bt->lchild == nullptr)
            return nullptr;
        else
            return SearchBST(bt->lchild, key);
    }
} //查找值为k的结点,返回值为k所在结点的地址

5.3哈夫曼(Huffman)编码

是一种编码方式,哈夫曼编码是可变字长编码的一种。

#include <climits> //INT_MAX
stack s[MaxSize];
struct HuffNode
{
    int weight;         //权值
    string word;        //权值对应的信息
    int parent;         //双亲所在数组下标
    int lchild, rchild; //左右孩子所在数组下标
};
class HuffTree
{
private:
    HuffNode hufftree[MaxSize + 1]; //huffman树的存储(1~2*n-1下标)
    int n;                          //权值个数
public:
    HuffTree(int w[], string str[], int n);     //初始化(权值,信息,个数)
    void SelectMinW(int n, int &min);           //选择最小权值的根结点所在下标
    void VisitHuffTree();                       //输出huffmantree
    int HuffCode(stack<char> s[]);          //设计haffman编码并计算wpl值(树的带权路径长度为树中所有叶子结点的带权路径长度之和),栈s[1]~s[n]存储各个权值的编码
    void DisplayAllCoding(stack<char> s[]); //输出各个权值的huffman编码
};
HuffTree::HuffTree(int w[], string str[], int n)
{
    int i, min1, min2;
    hufftree[0].weight = INT_MAX;
    hufftree[0].parent=-1;
    for (i = 1; i <= n; i++)
    {
        hufftree[i].weight = w[i];
        hufftree[i].word = str[i];
        hufftree[i].parent = -1;
        hufftree[i].lchild = -1;
        hufftree[i].rchild = -1;
    }
    for (; i <= 2 * n - 1; i++)
    {
        SelectMinW(i, min1);
        SelectMinW(i, min2);
        hufftree[i].lchild = min1;
        hufftree[i].rchild = min2;
        hufftree[i].weight = hufftree[min1].weight + hufftree[min2].weight;
        hufftree[i].parent = -1;
        hufftree[min1].parent = i;
        hufftree[min2].parent = i;
    }
    this->n = n;
}
void HuffTree::SelectMinW(int n, int &min)
{
    min = 0;
    for (int i = 1; i <= n; i++)
        if (hufftree[i].parent == -1 && hufftree[i].weight < hufftree[min].weight)
            min = i;
    hufftree[min].parent = 0; //避免下一次重复被选
}
void HuffTree::VisitHuffTree()
{
    cout << "No\tweight\tparent\tlchild\trchild\n";
    for (int i = 1; i <= 2 * n - 1; i++)
    {
        cout << i << "\t" << hufftree[i].weight << "\t";
        cout << hufftree[i].parent << "\t";
        cout << hufftree[i].lchild << "\t" << hufftree[i].rchild << "\n";
    }
}
int HuffTree::HuffCode(stack<char> s[])
{
    int wpl(0);
    for (int i = 1; i <= n; i++)
    {
        int tmp(0), length(0), t;
        for (t = i; t <= 2 * n - 1; )
        {
            if (hufftree[hufftree[t].parent].lchild == t)
                s[i].push('0');
            else if (hufftree[hufftree[t].parent].rchild == t)
                s[i].push('1');
            t = hufftree[t].parent;
            length++;
            if (hufftree[t].parent == -1)
                break;
        }
        tmp = hufftree[i].weight * length;
        wpl += tmp;
    }
    return wpl;
} //设计haffman编码并计算wpl值,栈S[1]~S[n]存储各个权值的编码
void HuffTree::DisplayAllCoding(stack<char> s[])
{
    for (int i = 1; i <= n; i++)
    {
        cout << "Coding of " << hufftree[i].weight << "(" << hufftree[i].word << "):";
        while (!s[i].empty())
        {
            cout << s[i].top();
            s[i].Pop();
        }
        cout << endl;
    }
} //输出各个权值的huffman编码

5.4二叉排序树(递归)

template <class T>
struct BiNode
{
    DataType data;
    BiNode *lchild, *rchild;
};
template <class T>
class BiSortTree
{
public:
    BiSortTree(DataType r[], int n);                                 //建立关键字序列r[0]~r[n-1]的二叉排序树
    ~BiSortTree();                                                   //析构函数,释放二叉排序树中所有结点,同二叉链表的析构函数
    void InsertBST(BiNode<T> *&bt, T key);             //插入key
    BiNode<T> *SearchBST(BiNode<T> *bt, T key); //查找值为k的结点,返回值为k所在结点的地址
    void InOrderBST(BiNode<Te> *bt);                           //中序遍历二叉树(递归)
    BiNode<T> *GetRoot();                                     //获取root值

private:
    BiNode<T> *root;              //二叉排序树(即二叉链表)的根指针
    void Release(BiNode<T> *&bt); //析构函数调用
};

//构造函数,将r[0]~r[n-1]各个元素依次插入,生成一棵二叉排序树
template <class T>
BiSortTree<T>::BiSortTree(T r[], int n) //构造函数
{
    root = nullptr; //初始化空二叉树
    int i;
    for (i = 0; i < n; i++)
    {                          //进行n次插入
        InsertBST(root, r[i]); //将结点s插入到二叉排序树中
    }
}

//析构函数,调用Release释放内存
template <class T>
BiSortTree<DataType>::~BiSortTree()
{
    Release(root);
}

//释放二叉排序树的存储空间,调用析构函数实现
template <class T>
void BiSortTree<T>::Release(BiNode<T> *&bt)
{
    if (bt)
    {
        Release(bt->lchild); //释放左子树
        Release(bt->rchild); //释放右子树
        delete bt;
    }
}

template <class T>
BiNode<T> *BiSortTree<T>::GetRoot()
{
    return root;
}

template <class T>
void BiSortTree<T>::InOrderBST(BiNode<T> *bt)
{
    if (bt == nullptr)
        return;
    else
    {
        InOrderBST(bt->lchild);
        cout << bt->data << " ";
        InOrderBST(bt->rchild);
    }
}
template <class T>
void BiSortTree<T>::InsertBST(BiNode<T> *&bt, T key)
{
    if (bt == nullptr)
    {
        BiNode<T> *tmp = new BiNode<T>;
        tmp->data = key;
        tmp->lchild = nullptr;
        tmp->rchild = nullptr;
        bt = tmp;
    }
    else
    {
        if (bt->data < key)
        {
            if (bt->rchild == nullptr)
            {
                BiNode<T> *tmp = new BiNode<T>;
                tmp->data = key;
                tmp->lchild = nullptr;
                tmp->rchild = nullptr;
                bt->rchild = tmp;
            }
            else
                InsertBST(bt->rchild, key);
        }
        else if (bt->data > key)
        {
            if (bt->lchild == nullptr)
            {
                BiNode<T> *tmp = new BiNode<T>;
                tmp->data = key;
                tmp->lchild = nullptr;
                tmp->rchild = nullptr;
                bt->lchild = tmp;
            }
            else
                InsertBST(bt->lchild, key);
        }
        else if (bt->data == key)
            return;
    }
} //插入key
template <class T>
BiNode<T> *BiSortTree<T>::SearchBST(BiNode<T> *bt, T key)
{
    if (bt == nullptr)
    {
        return nullptr;
    }
    else if (bt->data == key)
    {
        return bt;
    }
    else if (bt->data < key)
    {
        if (bt->rchild == nullptr)
            return nullptr;
        else
            return SearchBST(bt->rchild, key);
    }
    else if (bt->data > key)
    {
        if (bt->lchild == nullptr)
            return nullptr;
        else
            return SearchBST(bt->lchild, key);
    }
} //查找值为k的结点,返回值为k所在结点的地址

5.5二叉排序树(非递归)

template <class T>
struct BiNode
{
    T data;
    BiNode *lchild, *rchild;
};

//BiSortTree
template <class T>
class BiSortTree
{
public:
    BiSortTree(T r[], int n);     //建立关键字序列r[0]~r[n-1]的二叉排序树
    ~BiSortTree();                //析构函数,释放二叉排序树中所有结点,同二叉链表的析构函数
    void InsertBST(BiNode<T> *s); //插入结点*s
    BiNode<T> *SearchBST(T k);    //查找值为k的结点,返回值为k所在结点的地址
    void InOrderBST()             //中序遍历
    {
        InOrderBST(root); //调用私有中序递归函数
    }

private:
    BiNode<T> *root;                //二叉排序树(即二叉链表)的根指针
    void Release(BiNode<T> *&root); //析构函数调用
    void InOrderBST(BiNode<T> *root);
};

//构造函数,将r[0]~r[n-1]各个元素依次插入,生成一棵二叉排序树
template <class T>
BiSortTree<T>::BiSortTree(T r[], int n) //构造函数
{
    root = NULL; //初始化空二叉树
    int i;
    for (i = 0; i < n; i++)
    { //进行n次插入
        BiNode<T> *s;
        s = new BiNode<T>;
        s->data = r[i];
        s->lchild = s->rchild = NULL;
        InsertBST(s); //将结点s插入到二叉排序树中
    }
}

//中序遍历叉排序树,通过中序遍历是否为递增序列来验证构造的二叉排序树是否正确
template <class T>
void BiSortTree<T>::InOrderBST(BiNode<T> *root)
{
    if (root)
    {
        InOrderBST(root->lchild);
        cout << root->data << " ";
        InOrderBST(root->rchild);
    }
}

//析构函数,调用Release释放内存
template <class T>
BiSortTree<T>::~BiSortTree()
{
    Release(root);
}

//释放二叉排序树的存储空间,调用析构函数实现
template <class T>
void BiSortTree<T>::Release(BiNode<T> *&root)
{
    if (root)
    {
        Release(root->lchild); //释放左子树
        Release(root->rchild); //释放右子树
        delete root;
    }
}
template <class T>
void BiSortTree<T>::InsertBST(BiNode<T> *s)
{
    if (root == NULL)
        root = s;
    else
    {
        BiNode<T> *pos = root;
        while (pos != NULL)
        {
            if (pos->data == s->data)
                return;
            else if (pos->data < s->data)
            {
                if (pos->rchild == NULL)
                {
                    pos->rchild = s;
                    return;
                }
                else
                    pos = pos->rchild;
            }
            else if (pos->data > s->data)
            {
                if (pos->lchild == NULL)
                {
                    pos->lchild = s;
                    return;
                }
                else
                    pos = pos->lchild;
            }
        }
    }

} //插入结点*s
template <class T>
BiNode<T> *BiSortTree<T>::SearchBST(T k)
{
    BiNode<T> *pos;
    pos=root;
    while (pos!=NULL)
    {
        if(pos->data==k)
            return pos;
        else if(pos->data>k)
        {
            if(pos->lchild==NULL)
                return NULL;
            else
                pos=pos->lchild;
        }
        else if(pos->data<k)
        {
            if(pos->rchild==NULL)
                return NULL;
            else
                pos=pos->rchild;
        }
    }
    return NULL;
} //查找值为k的结点,返回值为k所在结点的地址

6.图

图分为有向图与无向图,存储方式有邻接矩阵、邻接表。

深度优先遍历DFSTraverse

广度优先遍历BFSTraverse

入度与出度。

6.1图的邻接矩阵

template <class T>
class Graph
{
public:
    Graph(T a[], int n, int e); //构造函数,初始化具有n个顶点,e条边的图
    void DispGraph();           //输出图中顶点值和矩阵值

    void DFSTraverse(int v); //    从v顶点出发深度优先遍历图(一个连通子图)

    void BFSTraverse(int v); //     从v顶点出发广度优先遍历图(一个连通子图)

private:
    T vertex[MaxSize];         //存放图中顶点信息的数组
    int arc[MaxSize][MaxSize]; //存放图中顶点关系(边)的数组
    int vertexNum, arcNum;     //图的顶点数和边数
};

//构造一个邻接矩阵存储的无向图
template <class T>
Graph<T>::Graph(T a[], int n, int e)
{
    vertexNum = n; //顶点数
    arcNum = e;    //边数
    int i, j, k;
    for (i = 0; i < vertexNum; i++)
        vertex[i] = a[i];           //顶点值
    for (i = 0; i < vertexNum; i++) //初始化邻接矩阵值为0(顶点间无边)
        for (j = 0; j < vertexNum; j++)
            arc[i][j] = 0;
    for (k = 0; k < arcNum; k++) //依次输入e条边
    {
        cin >> i >> j; //输入各条边依附的两个顶点的序号
        arc[i][j] = 1; //置有边标志
        arc[j][i] = 1;
    }
}

//输出图中所有顶点信息,和边信息
template <class T>
void Graph<T>::DispGraph()
{
    int i, j;
    cout << "  ";
    for (i = 0; i < vertexNum; i++)
        cout << vertex[i] << " "; //输出图中所有的顶点
    cout << endl;
    for (i = 0; i < vertexNum; i++)
    {
        cout << vertex[i] << " ";
        for (j = 0; j < vertexNum; j++)
            cout << arc[i][j] << " "; //输出边值(0/1)
        cout << endl;
    }
}
template <class T>
void Graph<T>::DFSTraverse(int v)
{
    queue<int> q;
    q.push(v);
    cout << vertex[v] << " ";
    visited[v] = 1;
    for (int i = 0; i < vertexNum; i++)
    {
        if (visited[i] == 0 && arc[v][i] == 1)
            DFSTraverse(i);
    }
} //    从v顶点出发深度优先遍历图(一个连通子图)
template <class T>
void Graph<T>::BFSTraverse(int v)
{
    queue<int> q;
    q.push(v);
    visited[v] = 1;
    while (!q.empty())
    {
        int j = q.front();
        cout << vertex[j] << " ";
        q.pop();
        for (int i = 0; i < vertexNum; i++)
        {
            if (visited[i] == 0 && arc[j][i] == 1)
            {
                visited[i] = 1;
                q.push(i);
            }
        }
    }
} //     从v顶点出发广度优先遍历图(一个连通子图)

6.2有向图的邻接表

int visited[MaxSize];   //访问标志数组(0表示未访问,1表示已访问)

//定义边表结点
struct ArcNode
{
   int adjvex;    //邻接点的序号
   ArcNode *next; //指向下一个边结点的指针
};

//定义顶点表结点
template <class T>
struct VertexNode
{
   T vertex;           //顶点的名称
   ArcNode *firstedge; //指向第一个边表结点的头指针
};

//邻接表类
template <class T>
class ALGraph
{
public:
   ALGraph(T a[], int n, int e); //构造函数,初始化一个有n个顶点e条边的图
   ~ALGraph();                   //析构函数,释放邻接表中各边表结点的存储空间
   void DispALGraph();           //输出邻接表
   void CountInD(int ind[]);     //计算各个顶点的入度,存储在ind中
   void CountOutD(int outd[]);   //计算各个顶点的出度,存储在outd中
private:
   VertexNode<T> adjlist[MaxSize]; //存放顶点表的数组
   int vertexNum, arcNum;          //图的顶点数和边数
};
template <class T>
ALGraph<T>::ALGraph(T a[], int n, int e)
{
   arcNum = e;    //边数
   vertexNum = n; //顶点数
   int i, j;
   for (i = 0; i < vertexNum; i++)
   {
      adjlist[i].vertex = a[i];
      adjlist[i].firstedge = NULL;
   }
   for (int k = 0; k < arcNum; k++) //依次输入每一条边,并在相应边表中插入结点
   {
      cin >> i >> j; //输入边所依附的两个顶点的序号
      ArcNode *s = new ArcNode;
      s->adjvex = j;                  //生成一个边表结点s
      s->next = adjlist[i].firstedge; //将结点s插入到i号表的头结点之后
      adjlist[i].firstedge = s;
   }
}
template <class T>
ALGraph<T>::~ALGraph()
{
   for (int i = 0; i < vertexNum; i++)
   {
      ArcNode *p = adjlist[i].firstedge;
      while (p != NULL) //循环删除
      {
         adjlist[i].firstedge = p->next;
         delete p; //释放结点空间
         p = adjlist[i].firstedge;
      }
   }
}
template <class T>
void ALGraph<T>::DispALGraph()
{
   int i;
   ArcNode *p;
   cout << "Graph adjlist:" << endl;
   for (i = 0; i < vertexNum; i++)
   {
      cout << i << " " << adjlist[i].vertex << " "; //输出图中顶点的序号i及值
      for (p = adjlist[i].firstedge; p; p = p->next)
         cout << p->adjvex << " "; //输出i号顶点的邻接点的序号
      cout << endl;
   }
}

//计算各个顶点的入度
template <class T>
void ALGraph<T>::CountInD(int ind[])
{
   for (int i = 0; i < vertexNum; i++)
   {
      ind[i] = 0;
   }
   for (int i = 0; i < vertexNum; i++)
   {
      ArcNode *p = adjlist[i].firstedge;
      while (p != NULL)
      {
         ind[p->adjvex]++;
         p = p->next;
      }
   }
}
//计算各个顶点的出度
template <class T>
void ALGraph<T>::CountOutD(int outd[])
{
   for (int i = 0; i < vertexNum; i++)
   {
      outd[i] = 0;
   }
   for (int i = 0; i < vertexNum; i++)
   {
      ArcNode *p = adjlist[i].firstedge;
      while (p != NULL)
      {
         outd[i]++;
         p = p->next;
      }
   }
}

6.3无向图的邻接表

int visited[MaxSize];   //访问标志数组(0表示未访问,1表示已访问)
template <class T>
class ALGraph
{
public:
    ALGraph(T a[], int n, int e); //构造函数,初始化一个有n个顶点e条边的图
    ~ALGraph();                   //析构函数,释放邻接表中各边表结点的存储空间
    void DispALGraph();           //输出邻接表
    int Count();                  //计算连通分量个数,返回值为连通分量的个数(请大家自己测试)
    void DFSTraverse(int v);      //深度优先遍历图
    void BFSTraverse(int v);      //广度优先遍历图
private:
    VertexNode<T> adjlist[MaxSize]; //存放顶点表的数组
    int vertexNum, arcNum;          //图的顶点数和边数
};
template <class T>
ALGraph<T>::ALGraph(T a[], int n, int e)
{
    arcNum = e;    //边数
    vertexNum = n; //顶点数
    int i, j;
    for (i = 0; i < vertexNum; i++)
    {
        adjlist[i].vertex = a[i];
        adjlist[i].firstedge = NULL;
    }

    for (int k = 0; k < arcNum; k++) //依次输入每一条边,并在相应边表中插入结点
    {
        cin >> i >> j; //输入边所依附的两个顶点的序号
        ArcNode *s = new ArcNode;
        s->adjvex = j;                  //生成一个边表结点s
        s->next = adjlist[i].firstedge; //将结点s插入到i号表的头结点之后
        adjlist[i].firstedge = s;
        s = new ArcNode;
        s->adjvex = i;                  //生成一个边表结点s
        s->next = adjlist[j].firstedge; //将结点s插入到j号表的头结点之后
        adjlist[j].firstedge = s;
    }
}
template <class T>
ALGraph<T>::~ALGraph()
{
    for (int i = 0; i < vertexNum; i++)
    {
        ArcNode *p = adjlist[i].firstedge;
        while (p != NULL) //循环删除
        {
            adjlist[i].firstedge = p->next;
            delete p; //释放结点空间
            p = adjlist[i].firstedge;
        }
    }
}
template <class T>
void ALGraph<T>::DispALGraph()
{
    int i;
    ArcNode *p;
    cout << "Graph adjlist:" << endl;
    for (i = 0; i < vertexNum; i++)
    {
        cout << i << " " << adjlist[i].vertex << " "; //输出图中顶点的序号i及值
        for (p = adjlist[i].firstedge; p; p = p->next)
            cout << p->adjvex << " "; //输出i号顶点的邻接点的序号
        cout << endl;
    }
}
template <class T>
int ALGraph<T>::Count()
{
    int i, n = 0;

    for (i = 0; i < vertexNum; i++)
        visited[i] = 0;
    for (i = 0; i < vertexNum; i++)
    {
        if (!visited[i])
        {
            n++;
            BFSTraverse(i); //利用深度优先或广度优先遍历算法均可
        }
    }
    return n;
}

//在下面完成深度优先、广度优先遍历算法
template <class T>
void ALGraph<T>::DFSTraverse(int v)
{
    visited[v] = 1;
    cout << adjlist[v].vertex << " ";
    ArcNode *p = adjlist[v].firstedge;
    while (p != NULL)
    {
        if (visited[p->adjvex] == 0)
            DFSTraverse(p->adjvex);
        p = p->next;
    }

} //深度优先遍历图
template <class T>
void ALGraph<T>::BFSTraverse(int v)
{
    queue<int> q;
    q.push(v);
    visited[v] = 1;
    while (!q.empty())
    {
        int j = q.front();
        cout << adjlist[j].vertex << " ";
        q.pop();
        ArcNode *p = adjlist[j].firstedge;
        while(p!=NULL)
        {
            if(visited[p->adjvex]==0)
            {
                q.push(p->adjvex);
                visited[p->adjvex]=1;
            }
            p=p->next;
        }
    }

} //广度优先遍历图

7.散列表

散列表也叫哈希表,是根据关键码值而直接进行访问的数据结构。

散列函数(哈希函数):直接寻址法、数字分析法、平方取中法、折叠法、随机数法、除留余数法(主要学习)。

冲突处理方法:开放寻址法(线性探测法、二次探测法、伪随机数法)、再散列法、链地址法。

7.1线性探测法(数组实现)

class HashList
{
private:
	int ht[MaxSize]; // hashtable
public:
	int HashFunc(int k);   //hash function
	HashList();			   //consturctor
	void Display();		   //display
	int HashSearch(int k); //dynamic search k
	double HashASL();	   //search ASL
	bool Empty(int i);	   //judge empty
};
//hash function
int HashList::HashFunc(int k)
{
	return k % MaxSize; //hash函数,假设为除余法,余数为MaxSize
}
//constructor:initialize an empty hashlist
HashList::HashList()
{
	int i;
	for (i = 0; i < MaxSize; i++)
		ht[i] = -1; //-1 is empty
}
void HashList::Display()
{
	int i;
	for (i = 0; i < MaxSize; i++)
		cout << ht[i] << " ";
	cout << endl;
}
double HashList::HashASL()
{
	double ASL = 0;
	int i, n = 0;
	for (i = 0; i < MaxSize; i++)
		if (ht[i] != -1)
		{
			ASL += HashSearch(ht[i]);
			cout << ht[i] << " " << HashSearch(ht[i]) << endl;
			n++;
		}
	//	cout<<ASL<<" "<<n<<endl;
	return ASL / n;
}
bool HashList::Empty(int i)
{
	return ht[i] == -1;
} //judge empty
int HashList::HashSearch(int k)
{
	int pos = HashFunc(k);
	int times = 1;
	while (!Empty(pos))
	{
		if (ht[pos] == k)
			return times;
		else
		{
			pos++;
			pos=pos%MaxSize;
			times++;
		}
		if (pos == HashFunc(k))
			throw "Overflow";
	}
	if (Empty(pos))
		ht[pos] = k;
	return times;
} //dynamic search k

7.2链地址法(指针实现)

struct Node
{
    int data;
    Node *next;
};
class LinkHash
{
public:
    LinkHash();            //initialize an empty list
    int HashFunc(int k);   //hash function
    int HashSearch(int k); //dynamic search k
    void Display();

private:
    Node *ht[MaxSize]; //ht数组用来保留各个链表的头指针
};
//hash function
int LinkHash::HashFunc(int k)
{
    return k % 11; //hash函数,假设为除余法,余数为11
}
//constructor:initialize an empty hashlist
LinkHash::LinkHash()
{
    int i;
    for (i = 0; i < MaxSize; i++)
    {
        ht[i] = nullptr; //empty pointer
    }
}
void LinkHash::Display()
{
    int i;
    for (i = 0; i < MaxSize; i++)
    {
        cout << "Hash address:" << i << ",value:";
        Node *p;
        stack<int> stk;
        for (p = ht[i]; p != nullptr; p = p->next)
            stk.push(p->data);
        while(!stk.empty())
        {
            cout<<stk.top()<<" ";
            stk.pop();
        }
        cout << endl;
    }
}
int LinkHash::HashSearch(int k)
{
    int times(1);
    int pos = HashFunc(k);
    Node *p = ht[pos];
    if (p == nullptr)
    {
        Node *s = new Node;
        s->next = nullptr;
        s->data = k;
        ht[pos] = s;
        return times;
    }
    while (p != nullptr && p->data != k)
    {
        if (p->next == nullptr && p->data != k)
        {
            Node *s = new Node;
            s->next = nullptr;
            s->data = k;
            p->next = s;
            return times;
        }
        p = p->next;
        times++;
    }
    if (p->data = k)
        return times;
} //dynamic search k

7.3线性探测法(指针实现)

struct Node
{
    int data;
    Node *next;
};

class LinkHash
{
public:
    LinkHash();            //initialize an empty list
    int HashFunc(int k);   //hash function
    int HashSearch(int k); //dynamic search k
    void Display();
    double HashASL();

private:
    Node *ht[MaxSize]; //ht数组用来保留各个链表的头指针
};

//hash function
int LinkHash::HashFunc(int k)
{
    return k % 11; //hash函数,假设为除余法,余数为11
}

//constructor:initialize an empty hashlist
LinkHash::LinkHash()
{
    int i;
    for (i = 0; i < MaxSize; i++)
        ht[i] = NULL; //NULL is empty
}
void LinkHash::Display()
{
    int i;
    for (i = 0; i < MaxSize; i++)
    {
        cout << "Hash address:" << i << ",value:";
        Node *p;
        stack<int> stk;
        for (p = ht[i]; p != NULL; p = p->next)
            stk.push(p->data);
        while (!stk.empty())
        {
            cout << stk.top() << " ";
            stk.pop();
        }
        cout << endl;
    }
}
int LinkHash::HashSearch(int k)
{
    int times(1);
    int pos = HashFunc(k);
    Node *p = ht[pos];
    if (p == NULL)
    {
        Node *s = new Node;
        s->next = nullptr;
        s->data = k;
        ht[pos] = s;
        return times;
    }
    while (p != NULL && p->data != k)
    {
        if (p->next == NULL && p->data != k)
        {
            Node *s = new Node;
            s->next = NULL;
            s->data = k;
            p->next = s;
            return times;
        }
        p = p->next;
        times++;
    }
    if (p->data = k)
        return times;
} //dynamic search k
double LinkHash::HashASL()
{
    double ASL(0);
    int n(0);
    for (int i = 0; i < MaxSize; i++)
    {
        Node *p;
        p = ht[i];
        while (p != NULL)
        {
            int tmp=HashSearch(p->data);
            ASL += HashSearch(p->data);
            p = p->next;
            n++;
        }
    }
    return ASL / n;
}

算法

1.排序算法

1.0排序算法说明

1.0术语说明

稳定 :如果a原本在b前面,而a=b,排序之后a仍然在b的前面;
不稳定 :如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面;
内排序 :所有排序操作都在内存中完成;
外排序 :由于数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行;
时间复杂度 : 一个算法执行所耗费的时间。
空间复杂度 :运行完一个程序所需内存的大小。

1.1拓扑排序

//邻接表类
template <class T>
class ALGraph
{
public:
    ALGraph(T a[], int n, int e); //构造函数,初始化一个有n个顶点e条边的图
    ~ALGraph();                   //析构函数,释放邻接表中各边表结点的存储空间
    void DispALGraph();           //输出邻接表
    void CountInD();              //计算各个顶点的入度,存储在adjlist[i].in中
    void DispInD();               //输出各顶点的入度
    void TopSort();               //拓扑排序,失败,抛出异常:Failure
private:
    VertexNode<T> adjlist[MaxSize]; //存放顶点表的数组
    int vertexNum, arcNum;          //图的顶点数和边数
};
template <class T>
ALGraph<T>::ALGraph(T a[], int n, int e)
{
    arcNum = e;    //边数
    vertexNum = n; //顶点数
    int i, j;
    for (i = 0; i < vertexNum; i++)
    {
        adjlist[i].vertex = a[i];
        adjlist[i].firstedge = NULL;
        adjlist[i].in = 0;
    }

    for (int k = 0; k < arcNum; k++) //依次输入每一条边,并在相应边表中插入结点
    {
        cin >> i >> j; //输入边所依附的两个顶点的序号
        ArcNode *s = new ArcNode;
        s->adjvex = j;                  //生成一个边表结点s
        s->next = adjlist[i].firstedge; //将结点s插入到i号表的头结点之后
        adjlist[i].firstedge = s;
    }
}
template <class T>
ALGraph<T>::~ALGraph()
{
    for (int i = 0; i < vertexNum; i++)
    {
        ArcNode *p = adjlist[i].firstedge;
        while (p != NULL) //循环删除
        {
            adjlist[i].firstedge = p->next;
            delete p; //释放结点空间
            p = adjlist[i].firstedge;
        }
    }
}
template <class T>
void ALGraph<T>::DispALGraph()
{
    int i;
    ArcNode *p;
    cout << "Graph adjlist:" << endl;
    for (i = 0; i < vertexNum; i++)
    {
        cout << i << " " << adjlist[i].vertex << " "; //输出图中顶点的序号i及值
        for (p = adjlist[i].firstedge; p; p = p->next)
            cout << p->adjvex << " "; //输出i号顶点的邻接点的序号
        cout << endl;
    }
}

//计算各个顶点的入度
template <class T>
void ALGraph<T>::CountInD()
{
    int i;
    ArcNode *p;
    for (i = 0; i < vertexNum; i++)
    {
        for (p = adjlist[i].firstedge; p != NULL; p = p->next)
        {
            adjlist[p->adjvex].in++;
        }
    }
}
//输出各个顶点的入度
template <class T>
void ALGraph<T>::DispInD()
{
    int i;
    cout << "In:";
    for (i = 0; i < vertexNum; i++)
        cout << adjlist[i].in << " ";
    cout << endl;
}
//topsort
/*
广度优先
template <class T>
void ALGraph<T>::TopSort()
{
    list<T> l;
    for (int i = 0; i < vertexNum;)
    {
        if (adjlist[i].in == 0)
        {
            adjlist[i].in = -1;
            l.push_back(adjlist[i].vertex);
            ArcNode *p;
            for (p = adjlist[i].firstedge; p != NULL; p = p->next)
            {
                adjlist[p->adjvex].in--;
            }
            i = 0;
        }
        else
            i++;
    }
    int sum(0);
    for (int i = 0; i < vertexNum;i++)
    {
        sum += adjlist[i].in;
    }
    if (sum == (-1) * vertexNum)
    {
        cout << "TopSort:";
        while (!l.empty())
        {
            cout << l.front() << " ";
            l.pop_front();
        }
    }
    else
        throw "Failure";
}
*/
template <class T>
void ALGraph<T>::TopSort()//深度优先
{
    list<T> l;
    stack<int> s;
    for (int i = 0; i < vertexNum; ++i) {
        if (adjlist[i].in == 0) {
            s.push(i);
        }
    }
    int visited = 0;
    while (!s.empty()) {
        ++visited;
        int u = s.top();
        s.pop();
        l.push_back(adjlist[u].vertex);
        for (ArcNode *p = adjlist[u].firstedge; p != NULL; p = p->next) {
            adjlist[p->adjvex].in--;
            if (adjlist[p->adjvex].in == 0) {
                s.push(p->adjvex);
            }
        }
    }
    if (visited == vertexNum)
    {
        cout << "TopSort:";
        while (!l.empty())
        {
            cout << l.front() << " ";
            l.pop_front();
        }
    }
    else
        throw "Failure";
}

1.2直接插入排序

有序区从前往后不断扩大,排序n-1次。

class List
{
private:
    int r[MaxSize + 1];
    int n;

public:
    List() { n = 0; }   //empty list
    void InsertR(int k) //表尾插入
    {
        r[++n] = k;
    }
    void Display();    //display
    void InsertSort(); //InsertSort
};
void List::Display()
{
    for (int i = 1; i <= n; i++)
        cout << r[i] << " ";
    cout << endl;
}
void exchange(int a[], int x, int num)
{
    int i;
    for (i = 1; i < num; i++)
    {
        if (x < a[i])
            break;
    }
    for (int j = num - 1; j >= i; j--)
    {
        a[j + 1] = a[j];
    }
    a[i] = x;
} //查找交换位置
void List::InsertSort()
{
    int i;
    for (i = 2; i <= n; i++)
    {
        if (r[i] < r[i - 1])
        {
            exchange(r, r[i], i);
        }
    }
} //InsertSort

1.3希尔排序

希尔排序是插入排序的一种又称“缩小增量排序”,是直接插入排序算法的一种更高效的改进版本,是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序,当增量减至 1 时,算法便终止。

class List
{
private:
    int r[MaxSize + 1];
    int n;

public:
    List() { n = 0; }   //empty list
    void InsertR(int k) //表尾插入
    {
        r[++n] = k;
    }
    void Display();   //display
    void ShellSort(); //ShellSort
};
void List::Display()
{
    for (int i = 1; i <= n; i++)
        cout << r[i] << " ";
    cout << endl;
}
void List::ShellSort()
{
    int i, j, k, l, mmin, tmp;
    for (j = 5; j >= 1; j = j - 2)//增量为5、3、1
    {
        for (i = 1; i <= j; i++)
        {
            for (k = i; k <= n - j; k += j)
            {
                mmin = k;
                for (l = k + j; l <= n; l += j)
                {
                    if (r[mmin] > r[l])
                        mmin = l;
                }
                tmp = r[mmin];
                r[mmin] = r[k];
                r[k] = tmp;
            }
        }
    }
} //ShellSort

1.4冒泡排序(起泡排序)

它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。

class List
{
private:
    int r[MaxSize + 1];
    int n;

public:
    List() { n = 0; }   //empty list
    void InsertR(int k) //表尾插入
    {
        r[++n] = k;
    }
    void Display();    //display
    void BubbleSort(); //BubbleSort
    bool dizeng();     //递增
};
void List::Display()
{
    for (int i = 1; i <= n; i++)
        cout << r[i] << " ";
    cout << endl;
}
void Exchange(int &a, int &b)
{
    int tmp;
    tmp = a;
    a = b;
    b = tmp;
}
bool List::dizeng()
{
    bool ret;
    ret = true;
    for (int i = 1; i < n; i++)
    {
        if (r[i] > r[i + 1])
            ret = false;
    }
    return ret;
}
void List::BubbleSort()
{
    int i;
    while (!dizeng())
    {
        for (i = 1; i < n ; i++)
        {
            if (r[i] > r[i + 1])
                Exchange(r[i], r[i + 1]);
        }
    }
} //BubbleSort

1.5快速排序

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

1.5.1递归实现
class List
{
private:
    int r[MaxSize + 1];
    int n;

public:
    List() { n = 0; }   //empty list
    void InsertR(int k) //表尾插入
    {
        r[++n] = k;
    }
    void Display();                     //display
    void QuickSort(int first, int end); //quickSort
    void QuickSort()
    {
        QuickSort(1, n);
    }
};

void List::Display()
{
    for (int i = 1; i <= n; i++)
        cout << r[i] << " ";
    cout << "\n";
}
void List::QuickSort(int first, int end)
{
    if (first > end)
        return;
    int left = first;
    int right = end;
    int tmp;
    //先移动轴值
    while (left < right)
    {
        while (left < right && r[left] <= r[right])
            right--;
        if (left < right)
        {
            tmp = r[left];
            r[left] = r[right];
            r[right] = tmp;
        }
        while (left < right && r[left] <= r[right])
            left++;
        if (left < right)
        {
            tmp = r[left];
            r[left] = r[right];
            r[right] = tmp;
        }
    }
    QuickSort(first, left - 1);
    QuickSort(left + 1, end);
    //后移动轴值
    /*
    while (left < right)
    {
        while (r[right] > tmp && left < right)
        {
            right--;
        }
        while (r[left] <= tmp && left < right)
        {
            left++;
        }
        if (left < right)
            swap(r[left], r[right]);
    }
    swap(r[first], r[right]);
    Display();
    QuickSort(first, left - 1);
    QuickSort(left+1 , end);
    */
} //quickSort
1.5.2利用栈实现
class List
{
private:
    int r[MaxSize + 1];
    int n;

public:
    List() { n = 0; }   //empty list
    void InsertR(int k) //表尾插入
    {
        r[++n] = k;
    }
    void Display();   //display
    void QuickSort(); //quickSort
};

void List::Display()
{
    for (int i = 1; i <= n; i++)
        cout << r[i] << " ";
    cout << endl;
}
void List::QuickSort()
{
    int first = 1;
    int end = n;
    stack<int> stk;
    stk.push(first);
    stk.push(end);
    int tmp;
    while (stk.size() >= 2)
    {
        int right = stk.top();
        stk.pop();
        int left = stk.top();
        stk.pop();
        int front = left;
        int back = right;
        while (left < right)
        {
            while (left < right && r[left] <= r[right])
                right--;
            if (left < right)
            {
                tmp = r[left];
                r[left] = r[right];
                r[right] = tmp;
            }
            while (left < right && r[left] <= r[right])
                left++;
            if (left < right)
            {
                tmp = r[left];
                r[left] = r[right];
                r[right] = tmp;
            }
        }
        if (front <back)
        {
            stk.push(front);
            stk.push(left-1);
            stk.push(left+1);
            stk.push(back);
        }
    }
} //quickSort

1.6简单选择排序

简单选择排序算法原理:每次从左至右扫描序列,记下最小值的位置。

class List
{
private:
    int r[MaxSize + 1];
    int n;

public:
    List() { n = 0; }   //empty list
    void InsertR(int k) //表尾插入
    {
        r[++n] = k;
    }
    void Display();    //display
    void SelectSort(); //SelectSort
};
void List::Display()
{
    for (int i = 1; i <= n; i++)
        cout << r[i] << " ";
    cout << endl;
}
void List::SelectSort()
{
    for (int i = 1; i < n; i++)
    {
        int mmin = i, tmp;
        for (int j = i; j <= n; j++)
        {
            if (r[j] < r[mmin])
                mmin = j;
        }
        tmp = r[i];
        r[i] = r[mmin];
        r[mmin] = tmp;
    }
} //SelectSort

1.7堆排序

堆排序是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

class List
{
private:
    int r[MaxSize + 1];
    int n;

public:
    List() { n = 0; }   //empty list
    void InsertR(int k) //表尾插入
    {
        r[++n] = k;
    }
    void Display();                  //display
    void HeapSort() { HeapSort(n); } //HeapSort
    void HeapSort(int n);
    void Heapify(int n, int i); //维护大顶堆的性质
};
void List::Display()
{
    for (int i = 1; i <= n; i++)
        cout << r[i] << " ";
    cout << endl;
}
void List::HeapSort(int n)
{
    int i;
    //建堆
    for(i=n/2;i>=1;i--)
    {
        Heapify(n,i);
    }
    //排序
    for(i=n;i>1;i--)
    {
        swap(r[i],r[1]);
        Heapify(i-1,1);
    }
}
void List::Heapify(int n, int i)
{
    int largest = i;
    int lchild = 2 * i;
    int rchild = 2 * i + 1;
    if (lchild <= n && r[largest] < r[lchild])
        largest = lchild;
    if (rchild <= n && r[largest] < r[rchild])
        largest = rchild;
    if(largest!=i)
    {
        swap(r[largest],r[i]);
        Heapify(n,largest);
    }
}

2.模式匹配算法

2.1BF算法

BF算法,即暴力(Brute Force)算法,是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,若相等,则继续比较S的第二个字符和 T的第二个字符;若不相等,则比较S的第二个字符和T的第一个字符,依次比较下去,直到得出最后的匹配结果。

string s1;//主串
string s2;//匹配串
bool success=false;
for (int i = 0; i <= s1.size() - s2.size(); ++i)
{
    int j;
    for (j = 0; j < s2.size(); ++j)
    {
        if (s1[i + j] != s2[j])
        {
            break;
        }
    }
    if (j == s2.size())
    {
        cout << "index = " << i << endl;
        success = true;
        break;
    }
}
if(success == false)
    cout << "failure" << endl;

从前使用的大多数都是BF算法,主串指针回溯,匹配效率低下,因此需要提出一种新的算法(KMP),使得串的匹配效率变高(主串指针不回溯)。

2.2KMP算法

KMP算法是一种改进的字符串匹配算法,KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数(或者nextval()函数)实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n)。

2.2.0next数组和nextval数组的定义与区别

​ KMP中next数组表示如果当前匹配不成功,匹配串移动到的位置,不考虑移动到的位置的数与当前位置数的关系。

​ KMP中nextval数组表示如果当前匹配不成功,匹配串移动到的位置,考虑移动到的位置的数与当前位置数的关系。

2.2.1next数组的计算
string s; 
cin >> s;
vector<int> next(s.size() + 1);
int i = 0, j = -1;
v[i] = j;
while (i < s.size())
{
    if (j == -1 || s[i] == s[j])
    {
        i++, j++;
        v[i] = j;
    }
    else
        j = v[j];
}
2.2.2nextval数组的计算
string s; 
cin >> s;
vector<int> nextval(s.size() + 1);
int i = 0, j = -1;
v[i] = j;
while (i < s.size())
{
    if (j == -1 || s[i] == s[j])
    {
        i++, j++;
        if (s[i] == s[j])
            v[i] = v[j];
        else
            v[i] = j;
    }
    else
        j = v[j];
}
2.2.3KMP算法的实现
string s1;//主串
string s2;//匹配串
cin >> s1 >> s2;
int i = 0, j = 0;
while (i < s1.size())
{
    if (j == -1 || s1[i] == s2[j])
    {
        // 如果到达标志位或者比较的字符相同
        ++i, ++j;
    }
    else
    {
        // 匹配失败后的跳转下标
        j = nextval[j];
    }

    if (j == s2.size())
    {
        cout << "index = " << i - j << endl;
        break;
        // j = v[j];
    }
}
if (j != s2.size())
{
    cout << "No found" << endl;
}

3.查找算法

  • 查找算法的实现

  • ASL值的计算(平均查找次数)

3.1二分查找(非递归)

//有序表类
class LinearSearch
{
public:
    LinearSearch() { n = 0; }
    ~LinearSearch() {}
    void Insert(int x);      //有序表的插入,使序列仍有序
    void DispList();         //输出表
    int Bin_Search(int key); //返回值为查找key值所需的比较次数
    double ASL_Bin_Search(); //计算ASL值
private:
    int r[MaxSize + 1]; //存储元素(r[1]~r[n]存储元素)
    int n;              //顺序表实际长度
};

//在有序表中插入元素x,使序列仍有序
void LinearSearch::Insert(int x)
{
    int i;
    if (n >= MaxSize) //表满不能插入
        throw "Overflow";
    r[0] = x;
    for (i = n; r[i] > x; i--)
        r[i + 1] = r[i]; //将i位置元素后移
    r[i + 1] = x;        //在位置i+1插入元素x
    n++;                 //线性表长度增1
}

//计算ASL
double LinearSearch::ASL_Bin_Search()
{
    int i, ASL = 0;
    for (i = 1; i <= n; i++)
        ASL += Bin_Search(r[i]); //累加各个元素所需的比较次数
    return 1.0 * ASL / n;
}

int LinearSearch::Bin_Search(int key)
{
    int ret = 0, left = 1, right = n, i;
    while (left <= right)
    {
        i = (left + right) / 2;
        if (r[i] == key)
        {
            ret++;
            break;
        }
        else if (r[i] > key)
        {
            right = i - 1;
        }
        else if (r[i] < key)
        {
            left = i + 1;
        }
        ret++;
    }
    return ret;
} //返回值为查找key值所需的比较次数
void LinearSearch::DispList()
{ 
    //输出线性表
    int i;
    cout << "Data:";
    for (i = 1; i <= n; i++)
        cout << r[i] << " ";
    cout << endl;
}

3.2二分查找(递归)

//有序表类
class LinearSearch
{
public:
    LinearSearch() { n = 0; }
    ~LinearSearch() {}
    void Insert(int x);                         //有序表的插入,使序列仍有序
    void DispList();                            //输出表
    int Bin_Search(int key);                    //调用下面的递归算法
    int Bin_Search(int low, int high, int key); //递归算法,成功返回位置,否则返回0
private:
    int r[MaxSize + 1]; //存储元素(r[1]~r[n]存储元素)
    int n;              //顺序表实际长度
};
//在有序表中插入元素x,使序列仍有序
void LinearSearch::Insert(int x)
{
    int i;
    if (n >= MaxSize) //表满不能插入
        throw "Overflow";
    r[0] = x;
    for (i = n; r[i] > x; i--)
        r[i + 1] = r[i]; //将i位置元素后移
    r[i + 1] = x;        //在位置i+1插入元素x
    n++;                 //线性表长度增1
}
void LinearSearch::DispList() //输出表
{
    int i;
    cout << "Data:";
    for (i = 1; i <= n; i++)
    {
        cout << r[i] << " ";
    }
    cout << endl;
}
//在下面补充实现折半查找算法(两个函数Bin_Search,1个形参和3个形参的各一个)
int LinearSearch::Bin_Search(int key)
{
    return Bin_Search(1, n, key);
} //调用下面的递归算法
int LinearSearch::Bin_Search(int low, int high, int key)
{
    if (low >= high)
        return 0;
    int mid = (low + high) / 2;
    if (r[mid] == key)
        return mid;
    else if (r[mid] > key)
        return Bin_Search(low, mid - 1, key);
    else if (r[mid] < key)
        return Bin_Search(mid + 1, high, key);
} //递归算法,成功返回位置,否则返回0

4.回溯算法

  • 回溯算法(backtrack)是一种选优搜索法,按选优条件向前搜索,以达到目标。(一般用于枚举、深度优先(DFS))
//以数字的枚举为例子
const int Maxsize = 100;
int n; //搜索大小
int a[Maxsize];
bool visited[Maxsize] = {false};
void DFS(int cur)
{
    if (cur == n)
    {
        for (int i = 0; i < n; ++i)
        {
            cout << a[i] << ' ';
        }
        cout << endl;
    }
    for (int i = 1; i <= n; i++)
    {
        if (!visited[i])
        {
            visited[i] = true;
            a[cur] = i;
            DFS(cur + 1);
            visited[i] = false; //回溯
        }
    }
}

5.并查集算法

并查集被很多人认为是最简洁而优雅的数据结构之一,主要用于解决一*元素分组的问题。它管理一系列不相交的集合,并支持两种操作:

  • 合并(Union):把两个不相交的集合合并为一个集合。
  • 查询(Find):查询两个元素是否在同一个集合中。
5.0初始化
int fa[Maxsize];
/*
inline是C++关键字,在函数声明或定义中,函数返回类型前加上关键字inline,即可以把函数指定为内联函数。
这样可以解决一些频繁调用的函数大量消耗栈空间(栈内存)的问题。
*/
inline void init(int n)
{
    for (int i = 1; i <= n; ++i)
        fa[i] = i;
}
5.1查询与合并
int find(int x)
{
    //注意赋值运算符=的优先级没有三元运算符?:高。
    return x == fa[x] ? x : (fa[x] = find(fa[x]));
}
int i;
cout << "Data:";
for (i = 1; i <= n; i++)
    cout << r[i] << " ";
cout << endl;

}


### 3.2二分查找(递归)

```cpp
//有序表类
class LinearSearch
{
public:
    LinearSearch() { n = 0; }
    ~LinearSearch() {}
    void Insert(int x);                         //有序表的插入,使序列仍有序
    void DispList();                            //输出表
    int Bin_Search(int key);                    //调用下面的递归算法
    int Bin_Search(int low, int high, int key); //递归算法,成功返回位置,否则返回0
private:
    int r[MaxSize + 1]; //存储元素(r[1]~r[n]存储元素)
    int n;              //顺序表实际长度
};
//在有序表中插入元素x,使序列仍有序
void LinearSearch::Insert(int x)
{
    int i;
    if (n >= MaxSize) //表满不能插入
        throw "Overflow";
    r[0] = x;
    for (i = n; r[i] > x; i--)
        r[i + 1] = r[i]; //将i位置元素后移
    r[i + 1] = x;        //在位置i+1插入元素x
    n++;                 //线性表长度增1
}
void LinearSearch::DispList() //输出表
{
    int i;
    cout << "Data:";
    for (i = 1; i <= n; i++)
    {
        cout << r[i] << " ";
    }
    cout << endl;
}
//在下面补充实现折半查找算法(两个函数Bin_Search,1个形参和3个形参的各一个)
int LinearSearch::Bin_Search(int key)
{
    return Bin_Search(1, n, key);
} //调用下面的递归算法
int LinearSearch::Bin_Search(int low, int high, int key)
{
    if (low >= high)
        return 0;
    int mid = (low + high) / 2;
    if (r[mid] == key)
        return mid;
    else if (r[mid] > key)
        return Bin_Search(low, mid - 1, key);
    else if (r[mid] < key)
        return Bin_Search(mid + 1, high, key);
} //递归算法,成功返回位置,否则返回0

4.回溯算法

  • 回溯算法(backtrack)是一种选优搜索法,按选优条件向前搜索,以达到目标。(一般用于枚举、深度优先(DFS))
//以数字的枚举为例子
const int Maxsize = 100;
int n; //搜索大小
int a[Maxsize];
bool visited[Maxsize] = {false};
void DFS(int cur)
{
    if (cur == n)
    {
        for (int i = 0; i < n; ++i)
        {
            cout << a[i] << ' ';
        }
        cout << endl;
    }
    for (int i = 1; i <= n; i++)
    {
        if (!visited[i])
        {
            visited[i] = true;
            a[cur] = i;
            DFS(cur + 1);
            visited[i] = false; //回溯
        }
    }
}

5.并查集算法

并查集被很多人认为是最简洁而优雅的数据结构之一,主要用于解决一*元素分组的问题。它管理一系列不相交的集合,并支持两种操作:

  • 合并(Union):把两个不相交的集合合并为一个集合。
  • 查询(Find):查询两个元素是否在同一个集合中。
5.0初始化
int fa[Maxsize];
/*
inline是C++关键字,在函数声明或定义中,函数返回类型前加上关键字inline,即可以把函数指定为内联函数。
这样可以解决一些频繁调用的函数大量消耗栈空间(栈内存)的问题。
*/
inline void init(int n)
{
    for (int i = 1; i <= n; ++i)
        fa[i] = i;
}
5.1查询与合并
int find(int x)
{
    //注意赋值运算符=的优先级没有三元运算符?:高。
    return x == fa[x] ? x : (fa[x] = find(fa[x]));
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值