数据结构
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]));
}