数据结构
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