数据结构--2--stack, heap, queue, tree

//堆栈 stack  一个有0个或多个元素的又穷线性表//长度为MaxSize 的堆栈Stack CreateStack(int MaxSize); //生成空栈表,最大MaxSizeint 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,否则返回0int IsEmpty(Stack S){    return (S->Next == NULL);}//将item压入堆栈Svoid 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等等抽象数据类型,堆栈后进先出,队列先进先出,堆有优先级的队列(可用数组,链表,完全二叉树表示),树的结构形式在查询中有优势。

相关推荐