ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2020-03-28 18:52:38  阅读:204  来源: 互联网

标签:结点 return struct BST tree queue ElementType Data stack


//堆栈 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等等抽象数据类型,堆栈后进先出,队列先进先出,堆有优先级的队列(可用数组,链表,完全二叉树表示),树的结构形式在查询中有优势。

 

标签:结点,return,struct,BST,tree,queue,ElementType,Data,stack
来源: https://www.cnblogs.com/zsyby/p/12588741.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有