//堆栈 stack 一个有0个或多个元素的又穷线性表
//长度为MaxSize 的堆栈
Stack CreateStack(int MaxSize); //生成空栈表,最大MaxSize
int IsFull(Stack S, int MaxSize); //判断堆栈S是否已满
void Push(Stack S, ElementType item); //将元素item压入堆栈
int IsEmpty(Stack S); //判断堆栈S 是否为空
ElementType Pop(Stack S); //删除并返回栈顶元素
//堆栈的顺序存储实现 -------------------------------------------------------------------------------------------------第一部分:堆栈
#define MaxSize <存储数据元素的最大个数>
typedef struct SNode *Stack;
struct SNode{
ElementType Data[MaxSize];
int Top
}
// 入栈
void Push(Stack PtrS, ElementType item)
{
if(Ptrs->Top == MaxSize-1){
printf("堆栈满");
return;
}
else{
PtrS->Data[++(PtrS->Top)] = item;
return;
}
}
//出栈
ElementType Pop(Stack PtrS)
{
if(PtrS->Pop == -1){
printf("堆栈空");
return ERROR; //ERROR是elementType的特殊值,标志错误
}
else
{
return(PtrS->Data[(PtrS->Top)--]);
}
}
//堆栈可用于函数调用及递归实现,深度优先搜索,回溯算法等。
//-------------------------------------------------------------------------------------------- 一个数组实现两个堆栈
//一个数组实现两个栈: 从数组两头开始向中间生长;
//当两个栈的栈顶指针相遇时,表示两个栈都满了
#define MaxSize<存储数据元素的最大个数>
struct DStack{ ElementType Data[MaxSize]; int Top1; //堆栈1的栈顶指针
int Top2; //堆栈2的栈顶指针
}S;
S.Top1 = -1; //此时空
S.Top2 = MaxSize; //此时空
//push入栈
void Push(struct DStack *PtrS, elementType item, int Tag)
{
if (PtrS->Top2 - PtrS->Top1 == 1){
printf("堆栈满");
return;
}
if(Tag == 1) PtrS ->Data[++(PtrS->Top1)] = item;
else PtrS->Data[--(PtrS->Top2)] = item;
}
//pop出栈
ElementType Pop( struck DStack *PTrS, int Tag )
{
if(Tag == 1 ){
if (PtrS->Top1 == -1) {
printf("堆栈1空");
return NULL;
}
else return PtrS->Data[(PtrS->Top1)--];
}
else{
if (PtrS->Top2 == MaxSize){
printf("堆栈2空");
return NULL;
}
else return PtrS->Data[(PtrS->Top2)++];
}
}
//----------------------------------------------------------------------------------------------------------链表实现堆栈
//stack 的链式存储-》单链表,叫链栈
//插入和删除操作只能在栈顶进行
typedef struct SNode *Stack;
struct SNode{
ElementType Data;
struct SNode *Next;
};
//堆栈初始化,建立空栈
Stack CreateStack()
{ //构建一个堆栈的头结点,返回指针
Stack S;
S = (Stack)malloc(sizeof(struct SNode));
S->Next = NULL;
return S;
}
//判断堆栈S是否为空,若空返回1,否则返回0
int IsEmpty(Stack S)
{
return (S->Next == NULL);
}
//将item压入堆栈S
void Push (ElementType item, Stack S)
{
struct SNode *TmpCell;
TmpCell = (struct SNode *)malloc(sizeof(struct SNode));
TmpCell->Element = item;
TmpCell->Next = S->Next;
S->Next = TmpCell;
}
//删除并返回栈顶
ElementType Pop(Stack S)
{
struct SNode *FirstCell;
ElementType Topelem;
if(IsEmpty(S)){
printf("堆栈空");
return NULL;
}
else{
FirstCell = S->Next;
S->Next = FirstCell->Next;
TopElem = FirstCell->Element;
free(FirstCell);
return TopElem;
}
}
//-------------------------------------------------------------------------------堆栈是后进先出,队列是先进先出
//---------------------------------------------------------------------------------------------------------------第二部分:队列
//队列,具有一定操作约束的线性表,只能在一端插入,而在另一端删除,先进先出
//顺序实现队列
#define MaxSize <存储数据元素的最大个数>
struct QNode{
ElementType Data[MaxSize];
int rear;
int front;
};
typedef struct QNode *Queue;
//判断环队列是否空或满,可只用前MaxSize-1, 或使用tag或Size标识。
//-------------------------------------------------------------------队列结构的操作
//第一种方式,入队列
void AddQ(Queue PtrQ, ElementType item)
{
if((PtrQ->rear+1)% MaxSize == PtrQ->front){
printf("队列满");
return;
}
PtrQ->rear = (PtrQ->rear+1)% MaxSize;
PtrQ->Data[PtrQ->rear] = item;
}
//出队列
ElementType DeleteQ( Queue PtrQ)
{
if (PtrQ->front == PtrQ->rear){
printf("队列空");
return ERROR;
}
else{
PtrQ->front = (PtrQ->front+1)%MaxSize;
return PtrQ->Data[PtrQ->front];
}
}
//--------------------------------------------------------------------------------链表实现队列
//单向链表实现队列,链表尾不能做删除
struct Node{
ElementType Data;
struct Node *Next;
};
struct QNode{ //链队列结构
struct Node *rear; //指向队尾
struct Node *front; //指向对头
};
typedef struct QNode *Queue;
Queue PtrQ;
//删除操作
ElementType DeleteQ(Queue PtrQ)
{
struct Node *FrontCell;
ElementType FrontElem;
if(PtrQ->front == NULL){
printf("队列空");
return ERROR;
}
FrontCell = PtrQ->front;
if(PtrQ->front == PtrQ->rear) PtrQ->front = PtrQ->rear =NULL; //若队列只有一个,删除后队列置空
else PtrQ->front = PtrQ->front->Next;
FrontElem = FrontCell->Data;
free(FrontCell);
return FrontElem;
}
//查找
//静态查找:集合中记录固定,没有插入和删除,只有查找
//动态查找:集合中记录是动态变化的,除查找还可能发生插入和删除
//-----------------------------------------------------------------------------------------------------第三部分:查找操作的讨论,二叉树
//------------------------------------------------------------------------------------------查找操作
//顺序查找的实现
int SequentialSearch (List Tb1, ElementType K)
{ //在Element[1]~[n]中查找关键字为K的数据元素
int i;
for(i = Tb1->Length; i>0&& Tb1->Element[i] != k;i--);
return i; //查找成功返回下标,不成功返回i
}
typedef struct LNode *List;
struct LNode{
ElementType Element[MAXSIZE];
int Length;
};
//顺序查找的一种实现:哨兵
//在边界放一个哨兵
int SequentialSearch (List Tb1, ElementType K)
{
int i;
Tb1->Element[0] = K; //建立哨兵
for(i = Tb1->Length; Tb1->Element[i]!= K;i--)
return i; //查找成功返回下标,不成功返回0
}
//---------------------------------------------------------------------------------------二分查找
//二分查找:先决条件:有序、连续存放(数组)
int BinarySeach(List Tb1, ElementType K)
{
int left, right, mid, NoFound = -1;
left = 1; //初始左边界
right = Tb1->Length; //初始右边界
while(left <= right)
{
mid = (left+right)/2; //计算中间元素坐标
if(K<Tb1->Element[mid]) right = mid-1; //调整右边界
else if (K>Tb1->Element[mid]) left = mid+1; //调整左边界
else return mid; //查找成功,返回数据元素下标
}
return NotFound; //查找不成功,返回-1
}
//--------------------------------------------------------------------------------判定树(从二分查找衍生)->查找的次数是该元素所在层数
//树更易实现动态查找
//结点的度:子树个数
//树的度:所有结点度最大的
//树的表示:儿子兄弟表示法 ->旋转45° 变成二叉树
//element:left ,right
//二叉树有左右之分,而一般的树没有
//树操作,有判断是否空,遍历和创建二叉树
//遍历有先序,中序,后序和层次遍历
//完全二叉树用顺序存储方便之处,是父子关系可通过序号关系查找;
//一般二叉树也可以先补充为满二叉树,用数组存储,但会造成空间浪费
//------------------------------------------------------------------------------------------------树的链表表示
//链表表示树
typedef struct TreeNode *BinTree;
typedef BinTree Position;
struct TreeNode{
ElementType Data;
BinTree Left;
BinTree Right;
}
//先序遍历
Void PreOrderTraversal( BinTree BT)
{
if(BT){
printf("%d", BT->Data);
PreOrderTraversal(BT->Left);
PreOrderTraversal(BT->Right);
}
}
//先序,中序,后序都是以根节点为入口,再以根结点为出口,只不过是什么时候访问(print)结点不同
//中序遍历非递归遍历算法
void InOrderTraversal(BinTree BT)
{
BinTree T = BT;
Stack S = CreateStack(MaxSize); //创建并初始化堆栈S
while(T || !IsEmpty(S)){
while(T){ //一直向左并将沿途压入堆栈
Push(S, T);
T = T->Left;
}
if(!IsEmpty(S)){
T = Pop(S);
printf("%5d", T->Data); //结点弹出堆栈
T = T->Right; //转向右子树
}
}
}
//层序遍历,通过队列实现,把结点进队,退出后,把左右儿子入队。
void levelOrderTraversal(BinTree BT)
{
Queue Q;
BinTree T;
if (!BT) return; //空树则直接返回
Q = CreateQueue(MaxSize); //创建并初始化队列Q
AddQ(Q, BT);
while (!IsEmptyQ(Q)){
T = DeleteQ(Q);
printf("%d\n", T->Data); //访问取出队列的结点
if (T->Left) AddQ(Q, T->Left);
if (T->right) AddQ(Q, T->Right);
}
}
//可以求叶子节点,二叉树高度
//二元运算表达式树,中缀表达式会受到运算优先级的影响,但可以加括号的方式避免
//-------------------------------------------------------------------------------------------二叉搜索树,左子树小,右子树大
//二叉搜索树,也称二叉排序树
//1.非空左子树的所有键值小于其根节点的键值
//2.非空右子树的所有键值大于其根节点的键值。
//3.左右子树都是二叉搜索树
//查找效率决定于树的高度
Position Find(ElementType X, BinTree BST)
{
if(!BST) return NULL; //空则返回NULL
if(X > BST->Data) return Find(X, BST->Right); //在右树继续查找
else if(X < BST->Data) return Find(X, BST->Left); //在左树继续查找
else return BST; //查找成功,返回找到的结点地址
}
//由于非递归函数的执行效率高,可将尾递归(return时递归)函数改为迭代函数,->循环
//最大元素是最右走到底,最小元素是最左走到底
Position IterFind(ElementType X, BinTree BST)
{
while(BST){
if(X > BST->Data) BST = BST->Right; //在右树继续查找
else if(X < BST->Data) BST = BST->Left; //在左树继续查找
else return BST; //查找成功,返回找到的结点地址
}
return NULL; //查找失败
}
//insert操作,如何插入到二叉搜索树
BinTree Insert(ElementType X, BinTree BST)
{
if(!BST){
BST = malloc(sizeof(struct TreeNode));
BST->Data = X;
BST->Left = BST->Right = NULL;
}else
if(X < BST->Data) BST->Left = Insert(X, BST->Left);
else if (X > BST->Data) BST->Right = Insert(X, BST->Right);
return BST;
}
//delete 操作
//删除叶子很简单,但删除结点,找左子树最大值或右子树最小值做结点
BinTree Delete(ElementTyoe X, BinTree BST)
{
Position Tmp;
if (!BST) printf("要删除元素未找到");
else if(X < BST->Data) BST->Left = Delete(X, BST->Left); //左子树递归删除
else if(X > BST->Data) BST->Right = Delete(X, BST->Right); //右子树递归删除
else //找到要删除节点
if (BST->Left && BST->Right){ //删除节点有两个子结点
Tmp = FindMin(BST->Right); //在右子树找最小元素填充被删除结点
BST->Data = Tmp->Data;
BST->Right = Delete(BST->Data, BST->Right); //在删除结点的右子树中删除最小元素
}
else{ //被删除结点有一个或无子结点
Tmp = BST;
if(!BST->Left) BST = BST->Right; //有右孩子或无子结点
else if(!BST->Right) BST = BST->Left; //有左孩子或无子结点
free(Tmp);
}
return BST;
}
//ASL 平均查找长度
//AVL树,平衡二叉树;平衡因子BF=hL-hR(对结点来说),任一结点左右子树高度差的绝对值不超过1. 复杂度log2(n)
//平衡二叉树调整,RR, LL, RL, LR旋转等
//summary:,完全二叉树(结点编号与满二叉树相同的),满二叉树(完美二叉树),二叉搜索树,平衡二叉树
//堆 heap
//优先队列priority queue, 取出元素的顺序依照元素的优先权大小。
//----------------------------------------------------------------------------------------------------------------第四部分:堆,有优先级的结构
//通过数组实现
typedef struct HeapStruct *MaxHeap;
struct HeapStruct{
ElementType *Element; //存储堆元素的数组
int Size; //堆的当前元素个数
int Capacity; //堆的最大容量
};
//创建一个堆
MaxHeap Create(int MaxSize)
{ //创建容量为Maxsize的空最大堆
MaxHeap H = malloc(sizeof(struct HeapStruct));
H->Elements = malloc((MaxSize+1)*sizeof(ElementType));
H->Size = 0;
H->Capacity = MaxSize;
H->Elements[0] = MaxData; //定义哨兵为大于堆中所有可能元素的值
return H;
}
//有序队列的完全二叉树表示堆,堆的两个特性,结构性:用数组表示的完全二叉树,有序性:任一结点的关键字是其子树所有结点的最大值(或最小值)
//数据插入堆
void Insert(MaxHeap H, ElementType item)
{ //将元素item插入最大堆H,其中H->Elements[0]定义为哨兵
int i;
if (IsFull(H)){
printf("最大值已满");
return;
}
i = ++H->Size; //i指向插入后堆中最后一个元素的位置
for(; H->ElementType[i/2] < item; i/2) H->Elements[i] = H->Elements[i/2]; //向下过滤结点
H->Elements[i] = item; //将item插入
}
//delete 操作
ElementType DeleteMax(MaxHeap H)
{ //从最大堆H中取出最大值,并删除
int Parent, Child;
ElementType MaxItem, temp;
if(IsEmpty(H)){
printf("最大堆已空");
return;
}
MaxItem = H->Elements[1];//取出最大值
temp = H->Elements[H->Size--];//用最大堆中最后一个元素从根节点向上过滤下层结点
for(Parent = 1; Parent*2 <= H->Size; Parent = Child){
Child = Parent*2;
if((Child != H->Size) &&
(H->Elements[Child] < H->Elements[Child+1]))
Child++; //child指向左右结点较大的
if(temp >= H->Elements[Child]) break;
else H->Elements[Parent] = H->Elements[Child]; //移动temp元素到下一层
}
H->Elements[Parent] = temp;
return MaxItem;
}
//huffman tree 霍夫曼树,霍夫曼编码等等,排序,每两个最小权重合并,构成左右子树,然后依次操作。
typedef struct TreeNode *HuffmanTree;
struct TreeNode{
int Weight;
HuffmanTree Left, Right;
};
HuffmanTree Huffman(MinHeap H)
{ //假设H->Size个权值已经存在H->Element[]->Weight中
int i;
HuffmanTree T;
BuildMinHeap(H); //将H->Element[]按权值调整为最小堆
for (i = 1; i < H->Size; i++){ //做H->Size -1次合并
T = malloc(sizeof(struct TreeNode)); //建一个新结点
T->Left = DeleteMin(H); //从最小堆删除一个结点,作为新T的左子结点
T->Right = DeleteMin(H); //从最小堆删除一个结点,作为新T的右子结点
T->Weight = T->Left->Weight + t->Right->Weight; //计算新权重
Insert(H, T); //将新T插入
}
T = DeleteMin(H);
return T;
}
//---------集合简单表示---------------------------------------------------
typedef struct {
ElementType Data;
int Parent;
}SetType;
//------------------------------------------------------------------------
//按秩归并与路径压缩 可提高算法的效率,但是路径压缩在数据量很大的情况下才能显示出优势来
//总结一下,数组与链表是存储最最基本的两种结构,由此衍生出stack, heap, queue, tree等等抽象数据类型,堆栈后进先出,队列先进先出,堆有优先级的队列(可用数组,链表,完全二叉树表示),树的结构形式在查询中有优势。