此博客用于记录第一次初步较浅层学习数据结构与算法的记录
更深入的C++数据结构学习 请访问 P2
文章目录
- 1 swap()算法
- 2 SelectSort()算法
- 3 BinarySearch()算法
- 4 List
- 5 linked_Stack
- 6: linked Queue
- 7: BinaryTree
- 8 Binary Search Tree
- 9 RedBlackTree
- 1:RBT头文件
- 2:异常处理头文件
- 3:包装引用头文件
- 10 Heap
- 1:MaxHeap头文件
- 2:堆排序
- 11 Gragh
- 1:Adjcent_Matrix and DFS BFS
- 2:Adjcent_List
- 12 Queue
- 1:Array_Queue
1 swap()算法
(1)内容: swap()算法的两种实现 swap函数(2)算法实现
// 引用传参
void myswap(int &x,int &y)
{
int p;
p=x; x=y; y=p;
} //注意事项:直接传递变量无法实现交换
// 2函数
swap(<class>x,<class>y);
2 SelectSort()算法
(1)内容:SelectSort()与冒泡排序都是低级排序方法。但是选择排序因为他较小的交换时间,比冒泡排序更加高效。
(2)函数分析
算法的思路: 就是通过遍历标记,每次循环只交换一次来减小时间消耗。 循环时两重循环,外层循环代表此时最小值(最大值)位置,内层循环用于遍历查找最小值。 查找最小之后,在外层循环结束前进行交换。
void SelectSort(int *a,int n)
{
for(int i=0;i<n-1;i++)
{
int Min=i;
for(int j=i+1;j<n;j++)
{
if(a[j]<a[Min] Min=j; //标记最小次序(不交换)
}
swap(a[Min],a[i]); //交换数值
}
}
(3)具体实现
#include <iostream>
using namespace std;
void SelectSort(int *a,int n)
{
for(int i=0;i<n-1;i++)
{
int Min=i;
for(int j=i+1;j<n;j++)
{
if(a[j]<a[Min])
{
Min=j; //找到最小数的序列
}
}
swap(a[i],a[Min]);
}
}
int main()
{
int a[10]={1,3,5,0,2,4,6,7,9,3};
SelectSort(a,10);
for(int i=0;i<10;i++)
cout<<a[i]<<' ';
cout<<endl;
cout<<endl;
}
3 BinarySearch()算法
(1)内容:二分法查找算法
(2)算法分析
二分法查找原理: 是一种非常快速的查找方式,但是查找的对象需要是已经排序的对象。 算法专注于mid点,每次查找mid点,如果查找的数据与mid位置处数据相同,则发挥mid值。 若数据大于Mid值数据,根据数据升序排列,应该是上限变成mid+1 . 若数据小于mid值,则是下限变成mid-1. 经过1/2 1/2 1/2 的收缩终于可以得到所需数据或者无法得到数据的提示。
int BinaryResearch(int *a,int x,int n)
{
int high=n,low=0;
int mid=0;
while(low<=high)
{
mid=(high+low)/2; //中间查找点
if(a[mid]==x)
{
return mid;
}
else if(a[mid]<x)
{
low=mid+1;
}
else if(a[mid]>x)
{
high=mid-1;
}
}
return -1; //执行结束没有结果返回-1
}
(3)具体实例
#include <iostream>
#include <algorithm>
using namespace std;
int BinarySearch(int *a,int x,int n)
{
int high, low, mid;
low=0; high=n-1;
while(low<=high)
{
mid=(high+low)/2;
if(a[mid]==x)
{
return mid;
}
else if(a[mid]<x)
{
low=mid+1;
}
else if(a[mid]>x)
{
high=mid-1;
}
}
return -1;
}
bool cmp(int &left,int &right)
{
if(left!=right) return (left<right);
}
int main()
{
int a[10]={9,8,7,6,5,4,3,2,1,0};
sort(a,a+10,cmp);
int result;
result=BinarySearch(a,8,10);
if(result==-1) cout<<"Not find"<<endl;
else cout<<result<<endl;
return 0;
}
4 List
(1)内容:链表的创建、链表的功能函数、迭代器
(2)链表的定义 and 基本创建
链表由 节点(数据、指针)、链表(功能、头指针)组成。 其中节点和链表可以为友元类或者节点嵌套在链表中,实现引用操作。
//friend
class NodeA
{};
class Node
{
public:
friend class List;
private:
int data; //数据
Node *next; //next指针
NodeA *nexta; //指向NodeA型指针
};
class List
{
public:
start();
private:
Node *first;
};
List::start()
{
Node *p = new Node(); //指针和空间
first = p; //头指针创建
p = new Node();
p->data=1;
first->next = p; //第一个节点创建
p = new Node();
p->data =2;
p->next = 0;
first->next->next = p; //第一个节点指向完成
}
//nesting
class List
{
public:
start();
private:
class Node
{
public:
friend class List;
//嵌套模型: public 亦可形成封装.
int data; //数据
Node *next; //next指针
NodeA *nexta; //指向NodeA型指针
};
class L
Node *first;
};
(3)链表的基本操作: 插入、删除、反转、连接
template<class Type> class List ;
template<class Type> class ListIterator;
template<class Type>
class Node
{
friend class List<Type>;
friend class ListIterator<Type>;
private:
Type data ;
Node<Type> *next;
Node(Type element) //私有构造函数
{
data = element;
}
};
template<class Type>
class List
{
friend class ListIterator<Type>;
public:
List() {first = 0 ;}; //指针赋值
void Insert(Type); //头插
void show() ;
void Delete(Type); //删除
void Invert(); //反转
void Concatenate(List<Type>); //连接
private:
Node<Type> *first;
};
插入算法解析(头插):
头插: 新节点成为first要求: 是first节点、next指向原first节点
template<class Type>
void List<Type>::Insert(Type k)
{
Node<Type> *p = new Node<Type>(k);
p->next = first ; //插在头部
first = p;
};
删除算法解析:
查找(指定对象)–>删除(占用空间)–>连接(头部删除直接改变first)
!!删除,增加一个left变量,可以实现删除指定对象占用的内存
template<class Type>
void List<Type>::Delete(Type k)
{
Node<Type> *left = 0;
Node<Type> *p =first;
while(p && p->data != k) //遍历查找
{
left = p;
p = p->next;
}
if(p) // p不是空指针(存在查找变量)
{
if(left) //非头部删除
{
left ->next = p ->next ; //连接
}
else //头部删除
{
first = first->next ;
}
delete p; //删除占用空间
}
};
转置算法解析:(a->b->c c->b->a)
转置: 颠倒next指向 a->b b->a,first->0
(一般需要上一个指针的都可以考虑上两个变量)
步骤:遍历颠倒:
1:next指向上一个指针 2:first指向末位指针
template<class Type>
void List<Type> :: Invert()
{
Node<Type> *p = first;
Node<Type> *left = 0;
while(p)
{
p ->next = left ;
p = p->next;
left = p;
//left p 先后移动
}
first = left ; //first颠倒
}
连接算法解析:
连接:a.Concatente(b) a+b
步骤: 查找末位指针–>连接b.first
1:a.first=0时, a=first = b.first; 2:b是List变量,不是指针!
template<class Type>
void List<Type>::Concatenate(List<Type> b)
{
Node<Type> *p = first;
if(!first){ first = b.first ; return ; }
while(p->next)
{
p = p->next ;
}
p ->next = b.first;
}
(4)测试代码
int main()
{
List<int> intList;
intList.Insert(5);
intList.Insert(15);
intList.Insert(25);
intList.Insert(35);
intList.Invert();
intList.show();
intList.Delete(25);
intList.show();
intList.Delete(20);
intList.show();
List<int> List2;
List2.Insert(4);
List2.Insert(6);
intList.Invert();
List2.Concatenate(intList);
List2.show();
return 0;
}
(5)链表的迭代器
迭代器:
public: 判断是否为空表、判断next是否为空
private: List(谁) Node(遍历)
①声明ListIterator类
//仍然使用上面定义的List类型
//注意:要在List and Node 中声明为友元类
template<class Type>
class ListIterator
{
public:
ListIterator<Type>(List<Type> l):list1(l),current(l.first) //构造函数
{
};
bool NotNull(); //判断表是否为空
bool NextNull(); //判断next指针是否为空
Type* First(); //迭代链表中节点数据指针
Type* Next();
void print(); //自定义的遍历输出函数
private:
List<Type> list1;
Node<Type> *current;
};
②定义成员函数
NotNull()函数: 判定链表是否为空–>头指针是否为空。
template<class Type>
bool ListIterator<Type>::NotNull()
{
if(list1.first) return true;
else return false;
}
NextNull()函数:判定下一个节点是否为空
若 当前节点不为空或下一节点不为空,返回true
else 返回 false
template<class Type>
bool ListIterator<Type>::NextNull()
{
if(current && current->next) return true;
else return false;
}
Type* First()函数:返回头指针所指节点数据
前提条件:头指针非空
template<class Type>
Type* ListIterator<Type>::First()
{
if(list1.first) return &list1.first->data;
else return 0;
}
Type* Next()函数:返回next节点data数据
前提条件: 当前节点非空,next非空
注意:由于next的当前指针非空故需要使用编列位置current(当前位置),同时使用完后会自动next一个节点
template<class Type>
Type* ListIterator<Type>::Next()
{
if(current && current->next)
{
current = current ->next;
return ¤t->data;
}
else return 0;
}
print()遍历输出函数:
template<class Type>
void ListIterator<Type>::print()
{
//遍历输出函数
cout<<* First();
while(NextNull()) //下一个节点非空输出
{
cout<<" -> "<<* Next(); //Next()自动进位
}
cout<<endl;
}
(6)具体代码
List<int> List2;
List2.Insert(15);
List2.Insert(25);
List2.Insert(35);
ListIterator<int> li(List2);
if(li.NotNull())
{
cout<< *li.First();
while(li.NextNull())
cout<<" -> "<<*li.Next(); //Next()函数内置递增,全部输出
cout<<endl;
}
(6)循环链表
循环链表的特点
1:first表头有存储空间,但没有存储data。头节点的next指针在空表时指向自身(first->next=first)。
2:first头节点始终在前面,插入的新节点在头节点的后面。且末位节点next指向first节点(left->next=first->next p->next=left->next)
3:相比于单向链表,循环链表对Inert() Delete()函数有修改 但是没有Invert() Concatente()函数
4:相比于单向链表,循环链表的迭代器的四个功能都存在改变。 循环链表自身的本身的构造函数也存在变化(new and circular)
①循环链表类(Node+List+Iterator)
template<class Type> class List ;
template<class Type> class ListIterator;
template<class Type>
class Node
{
friend class List<Type>;
friend class ListIterator<Type>;
private:
Type data ;
Node<Type> *next;
Node(Type);
Node(){}; //增加默认构造函数
};
template<class Type>
class List
{
friend class ListIterator<Type>;
public:
List() {first = new Node<Type>(); first->next= first; };
//为first节点新开辟空间,并使其next指针指向自己
void Insert(Type); //头插
void Delete(Type); //删除
private:
Node<Type> *first;
};
template<class Type>
class ListIterator
{
public:
ListIterator(List<Type>l):list1(l),current(l->first)
{};
bool NotNull();
bool NextNull();
Type* First();
Type* Next()
private:
List<Type> list1; //指定链表
Node<Type> *current; //节点指针方便调用
};
②循环链表函数
1:List::Insert(k)
插入函数算法:插入到first后第一个元素
关键:新插入的元素next指向原first指向节点
步骤:创建新节点–>连接next–>连接first
template<class Type>
void List<Type>::Insert(Type k)
{
Node<Type> *p = new Node<Type>(k);
p->next = first->next;
//当在空表插入时,next自然指向first
first->next = p;
}
2:List::Delete(k)
删除函数算法:删除指定数据的节点
关键: 1 循环的结束与普通链表不同,一次循环结束重新回到头节点 2 left+p双指针方便连接
步骤:查找–>连接–>删除
template<class Type>
void List<Type>::Delete(Type k)
{
Node<Type> * p = first->next;
Node<Type> *left = first;
while(p->data != k && p !=first )
{
left = p;
p = p->next;
} //遍历查找
if(p!=fist) //查找到
{
left->next = p->next; //连接
delete p; //删除
}
}
3:ListIterator::NotNull()
空表判断函数:判断循环链表是否为空
关键: 循环链表头节点next指向自身
template<class Type>
bool ListIterator<Type>::NotNull()
{
if(first->next != first) return true;
//if(curren->next != first)
else return false;
}
4:ListIterator::NextNull()
Next节点判断函数:判断next节点是否first
关键:循环节点next一定非空
template<class Type>
bool ListIterator<Type>::NextNull()
{
if(current->next != list1.first) return true;
//current:当前节点,NextNull也是判断当前节点情况
else return false;
}
5:ListIterator::First()
First():返回第一个节点数据的指针
关键:头节点没有数据。
注意:此时是迭代器类的函数,数据成员只有current and list1
template<class Type>
Type* ListIterator<Type>::First()
{
if(current != list1.first) return ¤t->data;
else return 0;
}
6:ListIterator::Next()
Next():返回下一节点数据指针,并自动后移一位
关键: 下一位指针判断 and 自动后移
当下一位是头节点时,还应自动next一位
template<class Type>
Type* ListIterator<Type>::Next()
{
if(current->next == first) current = current->next;
current = current ->next;
//也可以先移位在判断
return ¤t->data;
}
(7)测试实例(主函数内容)
List<int> List2;
List2.Insert(15);
List2.Insert(25);
List2.Insert(35);
ListIterator<int> li(List2);
if(li.NotNull()) //迭代器循环输出
{
cout<<*li.First();
while(li.NextNull())
{
cout<<" -> "<<*li.Next();
}
cout<<endl;
}
cout<<"测试一下循环"<<endl;
ListIterator<int> iter(List2);
cout<< *iter.First()<<endl;
cout<< *iter.Next()<<endl;
cout<< *iter.Next()<<endl;
cout<< *iter.Next()<<endl;
cout<< *iter.Next()<<endl;
return 0;
(8)双向链表原理
①双向链表类的创建
双向链表类
关键:节点有两个 right and left 指针
template class<Type> class DblList();
template<class Type>
class Node()
{
friend class DblList<Type>
private:
Type data;
Node<Type> *next;
Node<Type> *front;
};
class DblList()
{
public:
List()
{
first = new Node<Type>(); //代表头
first->front = first;
first->next = first;
}
void Inert(Node<Type> * , Node<Type> *);
void Delete(Node<Type> *);
private:
Node<Type> *first;
};
②双向链表插入删除函数
1:DblList::Insert()
节点插入函数: 插入新节点在右侧
关键:新节点and旧节点的指针
x <=> p <=>y
template<class Type>
void DblList<Type>::Inset(Node* p, Node* x)
{ //p在x右侧
p->next = x->next;
n->next->front = p;
x->next= p;
p->left = x;
//四个指针发生改变,先连接后面的节点啊
}
2:DblList::Delet()
节点删除函数: 删除指定节点
关键: 头节点不能删除
template<class Type>
void DblList<Type>::Delete(Node* x)
{
if(x==first)
ceer<<"Deletion of head node not permitted"<<endl;
else
{
x->front->next = x->next ;
delete x;
}
}
5 linked_Stack
(1)链式栈:相对于顺序栈可以修改栈中元素,不用担心栈中因为数组大小受限
(2)链式栈类
Linked_Stack = Node+Stack
Node:
private: data , next Node(); 与链表节点私有成员相同.
新产生的节点成为top节点
Stack:
public: IsEmpty() MakeEmpty() 空栈判断函数 Pop() Push() Top()三个基本操作函数
private: *top Node指针
template<class Type> class Stack;
template<class Type>
class Node
{
friend class Stack<Type>;
private:
Node(Type k , Node<Type>* p):data(k),next(p)
{};
//top节点有Stack创建,产生的新结点自上而下排列. 新产生的节点要指定其数据与next指针
Type data;
Node<Type> *next ;
};
template<class Type>
class Stack
{
public:
bool IsEmpty();
void MakeEmpty();
void Pop();
void Push(Type);
Type& Top();
Stack():top(0){};
//没有写=函数重载,直接赋值
~Stack() {MakeEmpty();};
private:
Node<Type> *top;
};
(3)链式栈函数
1:Stack::IsEmpty()
IsEmpty()函数: 判断栈是否为空
空栈: top=0
bool:可以返回逻辑值,也可以返回判断等式
template<class Type>
bool Stack<Type>::IsEmpty()
{
return top == 0;
}
2:Stack::MakeEmpty()
MakeEmpty()函数: 清理栈所用内存
算法思想: 遍历删除所有内存,直到为空表
while(! IsEmpty() )
template<class Type>
void Stack<Type>::MakeEmpty()
{
while(! IsEmpty() )
{ Pop(); }
//Pop()函数需要清空占用的内存
}
3:Stack::Push()****
Push()函数: 向栈中推入新节点
算法思路: 新产生的节点成为top,并将next指针指向原有top指针(由于Node()函数本身需要next指针指示,故仅仅需要new一个对象即可实现)
template<class Type>
void Stack<Type>::Push(Type k)
{
top = new Node<Type>(k, top);
//top_new->top_old
}
4:Stack::Pop()
Pop()函数: 删除顶部节点
关键: 空栈报错
正常删除后top位置的移动 :需要引进新的p=top
内存空间的清理
template<class Type>
void Stack<Type>::Pop()
{
if(IsEmpty() )
throw"Stack is Empty" ;
Node<Type> *p = top ;
top = top->next ;
delete p;
}
5:Stack::Top()
Top()函数:返回头部节点数据
关键: 空栈的报错
template<class Type>
Type& Stack<Type>::Top()
{
if(IsEmpty() )
throw"No DATA ";
return top->data;
}
(4)测试样例
cout<<"test linked stack"<<endl;
Stack<int> s;
s.Push(10);
cout<< s.Top()<<endl;
s.Push(20);
cout<< s.Top()<<endl;
s.Push(30);
s.Pop();
cout<< s.Top()<<endl;
return 0;
6: linked Queue
(1)队列特点
1:先进先出,先进先删除。使用完后删除内存
2:Queue中成员函数
IsEmpty() MakeEmpty()
DeQueue() EnQueue() GetQueue()
3: Queue+Node型
(2)链式队列类
template<class Type> class Node;
template<class Type>
class Node
{
friend class Queue<Type>
public:
Node(Type element , Node<Type> *n=0):data(element),next(n)
{};
private:
Type data;
Node<Type> *next;
};
template<class Type>
class Queue
{
public:
Queue();
~Queue();
bool IsEmpty();
void MakeEmpty();
Type & GetFront(); //返回front1
void EnQueue(); //插入值
Type DeQueue(); //删除front节点
private:
Node<Type>* front1;
Node<Type>* back1;
};
(3)函数分析
1:Queue::IsEmpty()
IsEmpty(): 判断队列是否为空
当front1 == 0是为空
template<class Type>
bool Queue<Type>::IsEmpty()
{
return front1==0 ;
}
2:Queue::MakeEmpty()
MakeEmpty(): 清空队列内存
循环清除
template<class Type>
void Queue<Type>::MakeEmpty()
{
if(! IsEmpty() )
DeQueue(); //删除
}
3:Queue::EnQueue()
EnQueue(): 排队插入函数,插入到尾端
关键: 空队列的插入front=back
区别: 相比于链表、栈,他插入在最后
template<class Type>
void Queue<Type>::EnQueue(Type k)
{
if(IsEmpty()
back1 = front1 = new Node<Type>(k);
else
back1-> next = new Node<Type>(k);
back1 = back1->next ;
}
4:Queue::DeQueue
DeQueue(): 头部删除函数
关键:节点删除算法
template<class Type>
Type Queue<Type>::DeQueue()
{
Type result = GetFront();
Node<Type> * p =front1;
front1 = front1->next;
delete p;
return result;
}
5:Queue::GetFront()
GetFront()函数: 返回队列首个节点数据
关键:空表的报错
template<class Type>
Type& Queue<Type>::GetFront()
{
if(IsEmpty())
throw"Queue is empty";
return front1->data;
}
6:Queue() ~Queue()
Queue(): 构造函数,初始化front1=back1=0
~Queue():析构函数 实现内存释放
template<class Type>
Queue<Type>::Queue()
{
back1 = front1 =0;
}
template<class Type>
Queue<Type>::~Queue()
{
MakeEmpty();
}
(4)样例测试
int main()
{
Queue<int> myQ;
myQ.EnQueue(10);
myQ.EnQueue(20);
myQ.EnQueue(30);
cout<<myQ.GetFront()<<endl;
myQ.DeQueue();
cout<<myQ.GetFront()<<endl;
return 0;
}
7: BinaryTree
(1)二叉树分析
二叉树 = 数组优点 + 链表优点,呈现左边数据小于右边数据
继承链表简便的增删改操作,有继承数组的二分查找,极大的提高代码运行速度
二叉树能存储的数据点个数: 2^n个(从第0层开始计算)
0->1 1->2 2->4 … 30->亿个
(2)函数分析(3递归+1queue)
二叉树主要的成员函数有:
InOrder()中序排列: 左子树+节点+右子树(子树按相同方式展开)
PreOrder()前序排列: 节点+左子树+右子树
PostOrder()后续排列: 左子树+右子树+节点
LevelOrder()层序排列: 从根节点开始,用queue形式先进先出,子树再解释
①二叉树类的建立
节点(public or struct) + BinaryTree
template<class Type> class BinaryTree;
template<class Type>
class Node
{
public:
Node()
{
left = NULL;
right = NULL;
};
Type data ;
Node<Type> *left;
Node<Type> *right;
};
template<class Type>
class BinaryTree
{
public:
void InOrder(); //中序排列
void InOrder(Node<Type> *p);
void PreOrder(); //前序排列
void PreOrder(Node<Type> *p);
void PostOrder(); //后序排列
void PostOrder(Node<Type> *p);
void LevelOrder();
void Visit(Node<Type> * p);
Node<Type> *root;
};
②1 前序排列、2 中序排列、3后序排列
1
template<class Type>
void BinaryTree<Type>::Visit(Node<Type> *p)
{
cout<< p->data ; //可视化操作
}
template<class Type>
void BinaryTree<Type>::InOrder()
{
InOrder(root);
}
template<class Type>
void BinaryTree<Type>::InOrder(Node<Type> *p)
{
if(p!=NULL)
{
//对整棵树进行中序排列,是从根节点到树的末尾的,即每个节点的左右子树都应该进行中序排列
InOrder(p->left);
Visit(p);
InOrder(p->right);
//递归的方法: 第一个节点排序,是显示此节点并对其左右节点也进行排序
}
}
2
template<class Type>
void BinaryTree<Type>::PreOrder()
{
PreOrder(root);
}
template<class Type>
void BinaryTree<Type>::PreOrder(Node<Type> *p)
{
if(p!=NULL)
{
Visit(p);
PreOrder(p->left);
PreOrder(p->right);
}
}
3
template<class Type>
void BinaryTree<Type>::PostOrder()
{
PostOrder(root);
}
template<class Type>
void BinaryTree<Type>::PostOrder(Node<Type> *p)
{
if(p!=NULL)
{
PostOrder(p->left);
PostOrder(p->right);
Visit(p);
}
}
三者的差异体现在对左右子树的排列的先后顺序与对应节点的可视化位置
③分层排序(queue)
template<class Type>
void BinaryTree<Type>::LevelOrder()
{
queue<Node<Type>*> q ;
Node<Type> p = root ;
//分层排序:从根节点到树末迭代,使用队列的方式进行左右子树的解析排序
while(p)
{
Visit(p); //队列头部
if(p->left!=NULL) q.push(p->left);
if(p->right!=NULL) q.push(p->right);
//讲左右子树的父节点塞入队列
if(q.empty()) return ;
p = q.front ;
//p =q.front 由于做左右子树在queue内先后排列,故先对左子树进行解析,
//是左子树能够排列输出到底然后再分层下到上考虑右子树
}
}
(3)测试代码
int main()
{
BinaryTree<char> tree;
Node<char> add,sub,mul,div,a,b,c,d,e;
add.data = '+';
sub.data = '-';
mul.data = '*';
div.data = '/';
a.data = 'A';
b.data = 'B';
c.data = 'C';
d.data = 'D';
e.data = 'E';
tree.root = &add;
add.left = ⊂
add.right = &e;
sub.left = &mul;
sub.right = &d;
mul.left = ÷
mul.right = &c;
div.left = &a;
div.right = &b;
cout<<"中序遍历:";
tree.InOrder();
cout<<"\n前序遍历:";
tree.PreOrder();
cout<<"\n后序遍历:";
tree.PostOrder();
cout<<"\n层序遍历:";
tree.LevelOrder();
return 0;
}
8 Binary Search Tree
(1)二叉查找树:
(1 拥有增、删、查的作用效果
(2 由BST Node Element三个类组成。其中BST实现二叉查找树功能,Node类储存指针与数据类,Element类实现一个节点多层数据的储存.
(2)函数分析
①二叉查找树类
template<class Type> class BST;
template<class Type>
class Element
{
public:
Type key;
//单独设计数据节点,实现数据多样化储存
};
template<class Type>
class Node
{
friend class BST<Type>;
private:
Node<Type> *left;
Node<Type> *right;
Element<Type> data;
};
template<class Type>
class BST
{
public:
BST(Node<Type> *init=0)
{
root = init ;
};
void InOrder();
void InOrder(Node<Type> *p);
void PreOrder(Node<Type> *p);
void PreOrder();
void PostOrder();
void PostOrder(Node<Type> *p);
void Visit(Node<Type> *p);
bool Insert(Element<Type> &x);
Node<Type>* Search(Elemen<Type> &x);
Node<Type>* Search(Node<Type> *,Elemen<Type> &x); //迭代查找
Node<Type>* IterSearch(Elemet<Type> &x);
//遍历查找
private:
Node<Type> *root;
};
②插入功能
算法分析:插入成功则返回1,失败则返回0.在数中不存在相同的节点数据,就可通过分叉操作进行插入.如果存在插入数据,则不能插入
由此可知:插入=查找位置+插入(low and fast)由于二叉树的特点,可以进行二分查找,分叉遍历查找的速度大大提高
low and fast指针的遍历可以通过同时指向next指针前进但是由于二叉树的分叉特点,low指针在选择分叉方向多余了.所以可以让low=fast , 再使得fast向前推进
template<class Type>
bool BST<Type>::Insert(Element<Type> &x)
{
Node<Type> *fast=root;
Node<Type> *low =NULL;
while(fast!=NULL)
{
low=fast;
if(x == fast->data.key) return false ;
else if(x < fast->data.key) fast = fast->left;
else if(x > fast->data.key) fast = fast->right;
}
//low fast指针迭代查找,得到指定位置与他的前一个位置
p = new Node<Type> ;
p->left = NULL;
p->right = NULL;
if(x < low->data.key) low->left = p;
else low->right =p;
return true;
}
③递归查找 (方法同三种排序方法)
Search(Element x)函数中仅仅给出了所要查找的数据值。而递归函数需要提供下一步操作的接口。故可以重新构造一个功能性递归函数,而这个函数就当作类的使用接口。
递归函数一般需要提供下一步的操作接口。若类中仅仅只有一个类的接口函数,不能进行递归运算,则可以自己创建一个函数,加上递归接口。
template<class Type>
Node<Type> BST<Type>::Search(Element<Type> &x)
{ //接口函数
Search(root,x);
}
template<class Type>
Node<Type> BST<Type>::Search(Node<Type> *b Element<Type> &x)
{
if(b == NULL) return 0;
if(x < b->data.key) Search(b->left,x);
if(x > b->data.key) Search(b->right,x);
if(x == b->data.key) return b;
}
④迭代查找
迭代查找就是从头到尾,利用二分性质循环查找的过程。由于二叉树的特性,迭代查找时间复杂度也不会太高。
template<class Type>
Node<Type> BST<Type>::IterSearch(Element<Type> &x)
{
Node<Type> p = root;
while( p != NULL)
{
if( p->data.key == x) return p;
if( p->data.key < x) p = p->right;
if( p->data.key > x) p = p-->left;
}
return 0;
}
9 RedBlackTree
(1)由于红黑树原始代码过长,故此处学习时采用逐步学习法。但最终呈现统一在一个代码内完成。
第一步: class RedBlackTree class RedBlackNode两个类 产生空的红黑树
第二步: 完善红黑树功能
1:RBT头文件
#ifn-def HEADREDBLACKTREE_H_INCLUDED
#define HEADREDBLACKTREE_H_INCLUDED
//调用前声明---------------------------
template<class Type> class RedBlackTree;
template<class Type> class RedBlackNode;
//------------------------------------
// class 红黑树
template<class Type>
class RedBlackTree
{
public:
typedef RedBlackNode<Type> Node; //由于节点定义过长,故可以定义一个较短的等价标志
enum {RED,BLACK}; //枚举颜色类型
RedBlackTree(const Type &negInf);
~RedBlackTree();
void Insert(const Type &x);
bool isEmpty() const ;
void makeEmpty();
void reclaimMemory(Node *t); //全部清空
Cref<Type> findMin() const;
Cref<Type> Find(const Type & x) const;
Cref<Type> findMax() const;
void rotateWithLeftChild(Node * &k2);
void rotateWithRightChild(Node * &k1);
void doubleRoateWithLeftChild(Node * &k3);
void doubleRotateWithRightChild(Node * &k4);
RedBlackTree<Type> * Rotate(const Type & item, Node *Parent);
void RedBlackTree<Type>::handleReotient(const Type &item);
private:
Node *header; //伪根,插入的第一个节点才是头节点
Node *nullNode; // 开辟一个空节点
Node *current;
Node *parent;
Node *grand;
Node *great;
}
//------------------------------------
// class 红黑树节点
template<class Type>
class RedBlackNode
{
public:
friend class RedBlackTree<Type>;
RedBlackNode(const Type& theElement,RedBlackNode<Type> *lt,RedBlackNode<Type> *rt,int c=RedBlackTree<Type>::BLACK):left(lt),right(rt),element(theElement),color(c)
{};
private:
RedBlackNode<Type> *left;
RedBlackNode<Type> *right;
Type element;
int color;
}
//------------------------------------
// 定义RedBlckTree的构造与析构函数
template<class Type>
RedBlacTree<Type>::RedBlackTree(const Type & negInf)
{
nullNode = new Node();
nullNode->left = nullNode->right = nullNode;
header = new Node(negInf);
header->left = header->right =nullNode;
}
template<class Type>
RedBlackTree<Type>::~RedBlackTree()
{
makeEmpty();
delete nullNode;
delete header;
}
//--------------------------------------
//查找函数------------------------------
template<class Type>
Cref<Type> RedBlackTree<Type>::findMin() const
{
if(isEmpty()) return Cref<Type>();
Node *itr = header->right;
while(itr->left != nullNode)
itr = itr->left;
return Cref<Type>(itr->element);
}
template<class Type>
Cref<Type> RedBlackTree<Type>::findMax() const
{
if(isEmpty()) return Cref<Type>();
Node *itr = header->right;
while(itr->right != nullNode)
itr = itr->right;
return Cref<Type>(itr->element);
}
template<class Type>
Cref<Type> RedBlackTree<Type>::Find(const Type& x) const
{
if(isEmpty()) return Cref<Type>();
nullNode->element =x ;
Node *p = header->right;
while(p!=nullNode)
{
if(x <p->element)
p = p->left;
else if(x > p->element)
p = p->right;
else if(x == p->element) break;
}
if(p != nullNode) return Cref<Type>(p->element);
else return Cref<Type>();
}
//--------------------------------------
//清楚函数--------------------------------
template<class Type>
bool RedBlackTree<Type>::isEmpty() const
{
return header->right==nullNode;
}
template<class Type>
void RedBlackTree<Type>::reclaimMemory(Node *t)
{
if(t != t->left)
{
reclaimMemory(t->left);
reclaimMemory(t->right);
delete t;
}
}
template<class Type>
void RedBlackTree<Type>::makeEmpty()
{
reclaimMemory(header->right);
}
//--------------------------------------
//插入函数--------------------------------
template<class Type>
void RedBlackTree<Type>::Insert()
{
//普通二叉树查找插入+自动平衡
current = parent = grand = header;
nullNode->element = x;
while(current->element != x) //找重复数据
{
great = grand;
grand = parent;
parent = current;
if(current->element <x) current = current->left;
if(current->element >x) current = current->right;
if(current->left->color ==RED && current->right->color == RED) //子节点都为红色
handleReorient(x);
}
//结束: nullNode or !nullNode
if(current != nullNode)
{
throw DuplicateItemException();
}
current = new Node(x,nullNode,nullNode);
if(x < parent->element) parent->left = current;
if(x > parent->element) parent->right = current;
handleReorient(x); //自动平衡
}
//--------------------------------------
//左转 右转函数--------------------------
template<class Type>
void RedBlackTree<Type>::rotateWithLeftChild(Node * &k2)
{
//内平移外旋转
Node * k1 = k2->left;
k2->left = k1->right;
k1->right = k2;
k2 = k1;
//改变头节点
}
template<class Type>
void RedBlackTree<Type>::rotateWithRightChild(Node * &k1)
{
Node *k2 = k1->right;
k1->right = k2->left;
k2->left = k1;
k1 = k2;
}
//--------------------------------------
//双旋转: 两次方向相反的旋转
template<class Type>
void RedBlackTree<Type>::doubleRotateWithLeftChild(Node * &k3)
{
// 右双旋转: left子节点左旋转 节点右旋转
rotateWithRightChild(k3->left);
rotateWithLeftChild(k3);
}
template<class Type>
void RedBlackTree<Type>::doubleRotateWithRightChild(Node * &k4)
{
rotateWithLeftChild(k4->right);
rotateWithRightChild(k4);
}
//--------------------------------------
//旋转集合函数-------------------------
RedBlacKNode<Type> * RedBlackTree<Type>::Rotate(const Type & item, Node *Parent)
{
if(item < Parent->element)
{
if(item < Parent->left->element) //右转
rotateWithLeftChild(Parent->left);
else rotateWithRightChild(Parent->left);
//左转
return Parent->left;
}
else
{
if(item < Parent->right->element)
rotateWithLeftChild(Parent->right);
else rotateWithRightChild(Parent->right);
return Parent->right;
}
}
//注意: 集合函数需要父节点,一般旋转操作包括 LL LR RL RR
//--------------------------------------
//--------------------------------------
//自动平衡函数 变色+旋转
void RedBlackTree<Type>::handeReorient(const Type &item)
{
current ->corlor = RED;
curren->left->color = current>right->color BLACK;
// 单旋转:外部孙子
// 双旋转:内部孙子
if(parent->colr == RED)
{
grand->color=RED;
if(item <grand->element != item <parent->element)
{
parent = Rotate(item,grand);
}
current = Rotate(item,great);
//人工双旋转
current->color = BLACK;
}
//--------------------------------------
#endif // HEADREDBLACKTREE_H_INCLUDED
2:异常处理头文件
#ifndef EXCEPT_H_INCLUDED
#define EXCEPT_H_INCLUDED
#include <string>
//异常处理类--------------------------------
class DSException
{
public:
DSException(const string &msg=""):massage(msg)
{};
virtual ~DSException();
virtual string toString() const
{
return "Exception" + string(": ")+what();
}
virtual string what() const
{
return message;
}
private:
string message;
}
//--------------------------------------
//重复异常处理--------------------------------
class DuplicateItemException: public DSEception
{
public:
DuplicateItemException(const string & msg=""):DSException(msg){};
};
//--------------------------------------
//空指针异常处理-------------------------
class NullPointerException:public DSEception
{
NullpointerException(const string &msg=""):DSExce[tion(msg) {};
};
#endif // EXCEPT_H_INCLUDED
3:包装引用头文件
#ifndef WRAPPER_H_INCLUDED
#define WRAPPER_H_INCLUDED
#include "Except.h"
template<class Type>
class Cref
{
public:
explicit Cref(const Type &x):obj(&x) {};
Cref():obj(NULL) {};
const Type & get() const
{
if(isNull()) throw NullpointerException();
else return *obj;
}
bool isNull() const
{
return obj == NULL;
}
private:
const Type *obj;
};
#endif // WRAPPER_H_INCLUDED
10 Heap
(1)堆是完全二叉树用数组实现的形式
主要的功能是插入Push 删除Pop()和排序。
其中Push 和 Pop 分别使用了向上渗透法和向下渗透法。
1:MaxHeap头文件
#ifndef HEADER_H_INCLUDED
#define HEADER_H_INCLUDED
//********************************************
//大顶堆类
template<class Type>
class MaxHeap
{
public:
Maxheap(int mx=10);
virtual ~Maxheap();
bool isEmpty();
void Push(const Type &x);
void Pop();
const Type& Top() const;
void trickleUp(int index);
void trickleDown(int index);
private:
Type *heapArray; //指针做数组
int maxSize;
int currentSize;
};
//********************************************
//构造、析构函数
template<class Type>
MaxHeap<Type>::MaxHeap(int mx)
{
if(mx<1) throw "max size must be >=10";
maxSize = mx;
currentSize = 0;
heapArray = new Type[maxSize];
}
template<class Type>
MaxHeap<Type>::~MaxHeap()
{
delete[] heapArray;
}
template<class Type>
bool MaxHeap<Type>::isEmpty()
{
return currentSize == 0;
}
//********************************************
//功能函数
template<class Type>
void MaxHeap<Type>::Push(const Type& x)
{
if(currntSize == maxSize) throw "MaxHeap is full";
heapArray[currentSize] = x;
trickleUp(currentSize);
currentSize++;
}
template<class Type>
const Type& MaxHeap<Type>::Top() const
{
return heapArray[0];
}
template<class Type>
void MaxHeap<Type>::Pop()
{
heapArray[0] = heapArray[--currentSize];
trickleDown(0);
}
//********************************************
//功能内部函数
void MaxHeap<Type>::trickleUp(int index)
{
int parent = (index-1)/2;
Type bottom = heapArray[index];
while(index > 0 && bottom < heapArray[parent)
{
heapArray[index] = heapArray[parent];
index = parent;
parent = (index-1)/2;
}
heapArray[index] = bottom;
}
template<class Type>
void MaxHeap<Type>::trikleDown(int index)
{
int largeChild = 0;
Type top = heapArray[0];
while(index < currentSize/2)
{
int leftChild = 2*index +1;
int rightChid = leftChild +1;
if(rightChild< currentSize && heapArray[rightChild]>heapArray[leftChild])
largeChild = rightChild;
else largeChild = leftChild;
if(top > heapArray[largeChild] break;
heapArray[index] = heapArray[largeChild];
index = largeChild;
}
heapArray[index] = top;
}
#endif // HEADER_H_INCLUDED
2:堆排序
一个一个输入堆中,从堆中取出来后已经自动排序
#include <iostream>
#include "header.h"
using namespace std;
int main()
{
MaxHeap<int> h(100);
int arr[] = {62,2,42,12,63,23,4,31,75,23};
for(int i=0;i<10;i++)
h.Push(arr[i]);
for(int i=0;i<10;i++)
{
arr[i] = h.Top();
h.Pop();
}
return 0;
}
11 Gragh
1:Adjcent_Matrix and DFS BFS
#ifndef MATRIX_H_INCLUDED
#define MATRIX_H_INCLUDED
#define MAX_VERTS 20
#include <iostream>
#include <stack>
#include <queue>
using namespace std;
//*******************************************
class Vertex
{
public:
Vertex(char lab):Label{lab) {wasVisited = false;};
char Label;
bool wasVisited;
};
class Gragh
{
public:
Gragh();
~Gragh();
void addEdge(int start,int end1);
void addVertex(char lab);
void printMarix();
void showVertex(int v);
void DFS();
void BFS();
private:
Vertex *vertexList;
int nVertex;
int adjmat[MAX_VERTS][MAX_VERTS];
int getAdjUnVisitedVertex(int v);
};
//*******************************************
Gragh::Gragh()
{
nVertex = 0;
for(int i=0;i<MAX_VERTS;i++)
{
for(int j=0;j<MAX_VERTS;j++)
adjmat[i][j][ = 0;
}
}
Gragh::~Gragh()
{
for(int i=0; i<nVertex;i++)
delete vertexList[i];
}
//*******************************************
void addVertex(char lab)
{
vertexList[nVertex++] = new Vertex(lab);
}
void addEdge(int start,int end1)
{
adjmat[start][end1] = 1;
adjmat[end1][start] = 1;
}
void printMatrix()
{
for(int i=0;i<nVertex;i++)
{
for(int j=0;j<nVertex;j++)
cout<<adjmat[i][j]<<" ";
cout<<endl;
}
}
//*******************************************
void Gragh::showVertex(int v)
{
cout<<vertexList[v]->Label<<" ";
}
int Gragh::getAdjUnVisitedVertex(int v)
{
for(int i=0;i<nVertex;i++)
{
if((adjMat[v][i] == 1) && (vertexList[v]->wasVisited == false))
return i;
}
return -1;
}
void Gragh::DFS()
{ //先进后出
stack<int> gStack;
vertextList[0]->Label = true;
showVertex(0);
gStack.push(0);
int v=0;
while(gStack.size()>0)
{
v = getAdjUnVisitedVertex(gStack.top());
if(v ==-1)
gStack.pop();
else
{
showVertex(v);
vertexList[v]->wasVisited = true;
}
}
for(int j=0;j<nVertex;j++)
vertexList[j]->wasVisited = false;
}
void Gragh::BFS()
{
queue<int> gQueue;
vertexList[0]->wasVisited = true;
showVertex(0);
gQueue.push(0);
int vert1 , vert2;
while(gQueue.size() >0)
{
vert1 = gQueue.front();
gQueue.pop();
vert2 = getAdhUnVisitedVertex(vert1);
while(vert2!=-1)
{
vertexList[vert2]->wasVisited = true;
showVertex(vert2);
gQueue.push(vert2);
vert2 = getAdhUnVisitedVertex(vert1);
}
}
cout <<endl;
for(int i=0;i<nVerts;i++)
vertexList[i]->wasVisited = false;
}
#endif // MATRIX_H_INCLUDED
2:Adjcent_List
#ifndef TABLE_H_INCLUDED
#define TABLE_H_INCLUDED
#include <list>
using namespace std;
template<class Type>
class Vertex
{
public:
Vertex(char lab):Label(lab) {};
private:
char Lable;
};
template<class Type>
ostream& operator<< (ostream& out,const Vertex<Type>& v)
{
cout<<v.Label;
return out;
}
template<class Type>
class Gragh
{
public:
Gragh(const int vertice):n(vertice);
{
VertexList = new Type*[n];
HeadNode = new list<int>[n];
nVerts = 0;
};
~Gragh()
{
delete[] VertexList;
delete[] HeadNode;
};
void addVertice(Type *v);
void addEdge(int start , int end1);
void printVertice();
void printAdjList();
private:
Type **VertexList;
list<int>* HeadNode;
int n; //总结点数
int nVerts; //现有节点数
};
//**************************************8
template<class Type>
void Gragh<Type>::addEdge(int start , int end1)
{
HeadNode[start].push_back(end1);
}
template<class Type>
void Gragh<Type>::addVertice(Type *v)
{
VertexList[nVerts++] = v;
}
template<class Type>
void Gragh<Type>::printVertice()
{
for(int i=0;i<nVerts;i++)
cout<<*VertexList[i]<<" ";
cout<<endl;
}
template<class Type>
void Gragh<Type>::printAdjList()
{
for(int i=0;i<nVerts;i++)
{
cout<<i<<" -> ";
for(list<int>::iterator iter = HeadNode[i].begin();iter!=HeadNode[i].end;++iter)
cout<<*iter<<" -> ";
cout<<"end"<<endl;
}
}
//**************************************8
#endif // TABLE_H_INCLUDED
12 Queue
1:Array_Queue
(1)数组型队列,使用动态数组(vector)与动态起始位置表示队列. 队列特征先进先出,主要有入队与出队两个操作,其中出队为删除头位置,入队是在末位插入。注意此时队列的非空判断是根据当前队列头位置与动态数组大小比较判断的。
(2)算法实现
#ifndef MYQUEUE_H_INCLUDED
#define MYQUEUE_H_INCLUDED
#include <iostream>
#include <vector>
using namespace std;
class MyQueue
{
public:
MyQueue() {p_start =0;};
bool IsEmpty();
bool EnQueue(int x);
bool DeQueue();
int Front();
private:
vector<int> data;
int p_start;
};
//**************************************
bool MyQueue::IsEmpty()
{
return p_start >= data.size();
//当开始节点>数组大小时,已经超出范围
}
int MyQueue::Front()
{
return data.at(p_start);
}
//**************************************
bool MyQueue::EnQueue(int x)
{
data.push_back(x);
return true;
}
bool MyQueue()::DeQueue()
{
if(IsEmpy()) return false;
p_star++;
return true;
}
#endif // MYQUEUE_H_INCLUDED