数据结构必背代码

1.二叉树的三种非递归

void PreorderWithOutRecursion(BiTree b){
   BiTNode* p;
   SqStack st;
    InitStack(st);
    p = b;
    while(!StackEmpty(st)||p!=NULL){
        while(p!=NULL){
            printf("%c",p->data);//先序打印
            Push(st,p);//打印之后进栈
            p = p->lchild;//左边孩子进栈进完
        }
        if(!StackEmpty(st)){
            Pop(st,p);//节点出栈
            p = p->rchild;//有右孩子就转向右孩子,等待下一步右孩子进栈然后再进右孩子的左孩子,没有p就是NULL,上面的循环会直接跳过,再次出栈,直到有右孩子再转向右孩子。
        }
    }
    printf("\n");

}
//PPT7.7:中序遍历非递归
void InOrderWithoutRecursion(BiTree b){
    BiTNode * p;
    SqStack st;
    InitStack(st);
    p = b;
    while(!StackEmpty(st)||p!=NULL){
        while(p!=NULL) {
            Push(st, p);//只管左边孩子全部进栈。
            p = p->lchild;
        }
        if(!StackEmpty(st)){
            Pop(st,p);//出栈一次
            printf("%c",p->data);//延后打印
            p = p->rchild;//搜索右孩子,如果没有右孩子p会为NULL,不会进入上一个循环,从而再次出栈,再次打印。直到有右孩子才转向右孩子。
        }

    }
    printf("\n");
}
////PPT7.7 后序遍历非递归
//在该节点的右孩子被处理之后,该节点则立即可以被访问。使用一个r指针来指向刚刚访问过的节点

void PostOrder1(BiTNode *b){    //后序非递归遍历算法
    BiTNode *p = b;
    BiTNode *r;
    bool flag;
    SqStack st;
    InitStack(st);
    do{
        while(p!=NULL){
            Push(st,p);
            p = p->rchild;
        }
        r = NULL;
        flag = true;
        while(!StackEmpty(st)&& flag){
            GetTop(st,p);//不着急访问,看这个节点的值。
            if(p->rchild == r){//没有右孩子||p的右孩子已经访问过
                printf("%c",p->data);//访问打印节点
                Pop(st,p);//节点出栈。
                r = p;//r指向刚刚访问过的节点。
            }else{
                p = p->rchild;//有右孩子就去处理右孩子。
                flag = false;//表示当前处理是右孩子,右孩子还没有被处理,所以不能从这里开始继续打印。(不是栈顶节点)
            }
        }
    } while (!StackEmpty(st));
    printf("\n");
}

2.图的深度优先,广度优先遍历

typedef struct Vertex{
    int edge;
}Vertex;
typedef struct ANode
{     int adjvex;            //该边的终点编号
    struct ANode *nextarc;    //指向下一条边的指针
    InfoType info;        //该边的权值等信息
}  ArcNode;

typedef struct Vnode
{    Vertex data;            //顶点信息
    ArcNode *firstarc;        //指向第一条边
}  VNode;

typedef struct
{     VNode adjlist[MAXV] ;    //邻接表
    int n,e;            //图中顶点数n和边数e
} AdjGraph;
void DFS(AdjGraph *G,int v)  
{      ArcNode *p; int w;        //顶点*p,定义一个w用来存序号。
       visited[v]=1;         //置已访问标记
       printf("%d  ",v);         //输出被访问顶点的编号
       p=G->adjlist[v].firstarc;         //p指向顶点v的第一条边的边头结点
       while (p!=NULL) 
       {      w=p->adjvex;        //w存了p的边的序号。每一步走到nextarc其实就已经跳换到列指定位置上面去了。
    if (visited[w]==0) 
           DFS(G,w);       //若w顶点未访问,递归访问它
    p=p->nextarc;      //p指向顶点v的下一条边的边头结点,就是切换到下一列上面去了。
      }
}
 void BFS(AdjGraph *G,int v)
{        int w, i;
         ArcNode *p;
         SqQueue *qu;        //定义环形队列指针
         InitQueue(qu);        //初始化队列
         int visited[MAXV];                //定义顶点访问标记数组
         for (i=0;i<G->n;i++) 
      visited[i]=0;          //访问标记数组初始化
         printf("%2d",v);         //输出被访问顶点的编号
         visited[v]=1;                  //置已访问标记
         enQueue(qu,v);
    while (!QueueEmpty(qu))           //队不空循环
       {    deQueue(qu,w);            //出队一个顶点w
    p=G->adjlist[w].firstarc;     //指向w的第一个邻接点
    while (p!=NULL)        //查找w的所有邻接点
    {     if (visited[p->adjvex]==0)     //若当前邻接点未被访问
           {    printf("%2d",p->adjvex);  //访问该邻接点
        visited[p->adjvex]=1;    //置已访问标记
        enQueue(qu,p->adjvex);    //该顶点进队
                      }
                      p=p->nextarc;                  //找下一个邻接点
    }
       }
       printf("\n");
}
    

3.二分搜索

typedef struct List{
    int data[maxsize];
    int  n1;
}List;
int binarySearch(List L,int k){
    int low =0,high = L.n1-1;
    while(low<high){
        int mid = (low+high)>>1;
        if(L.data[mid] == k) return mid+1;
        else if(L.data[mid]>k) high = mid-1;
        else low = mid+1;
    }
    return -1;
}

 4.kmp算法

void get_next(char T[], int next[]) {//算出next数组      
    int i = 1;
    next[1] = 0;
    int j = 0;
    while (i < T[0]) {
        if (j == 0 || T[i] == T[j]) {//j==0,说明再次回到了开头
            ++i, ++j;
            next[i] = j;//记录重复出现的位置。
        }
        else {
            j = next[j];
        }
    }
}
int KMP(char S[], char T[], int next[], int pos) {
    int i = pos;//开始查找的起始位置
    int j = 1;
    while (i<=S[0]&&j<=T[0]) {
        if (j == 0 || S[i] == T[j]) {//相等各自相加,往后走。
            ++i;
            ++j;
        }
        else {//不等,退回到next[j]位置
            j = next[j];//next[]就是用来存储下一次回退应该回退到那个地方。
        }
        if (j > T[0]) {//说明比对成功。
            return i - T[0];
        }
        else {
            return 0;
        }
    }
}

5.插入排序

void InsertSort(ElemType A[],int n) {//直接插入排序。
    int i, j;
    for (i = 2; i <= n;i++) {//第0个元素作为哨兵.不参与排序,。从第二个元素开始拿出,往前面插。
        if (A[i-1]> A[i]){//放到暂存/哨兵的位置。A[0]既是哨兵,又是暂存。
            A[0] = A[i];//哨兵存储当前比他前一位小的数字。
            for (j = i - 1; A[0] < A[j]; --j) {
                A[j + 1] = A[j];//这里是指定位置元素后移操作。
            }
            A[j + 1] = A[0];//最后把哨兵位置的值赋值给这一位。
        }
    }
}

6.冒泡排序

void BubbleSort(RecType R[],int n)
{      int i,j;  RecType temp;
       for (i=0;i<n-1;i++) 
       {
             for (j=n-1;j>i;j--)      //比较找本趟最小关键字的记录
                   if (R[j].key<R[j-1].key)   
         {     temp=R[j];        //R[j]R[j-1]
         R[j]=R[j-1];
         R[j-1]=temp;
        }
      }
} 

 

7.插入排序

void ShellSort(RecType R[],int n)
{   int i, j, d;
    RecType tmp;
    d=n/2;      //增量置初值
    while (d>0)
    {   for (i=d;i<n;i++)
        {      //对相隔d位置的元素组直接插入排序
               tmp=R[i];
     j=i-d;
     while (j>=0&&tmp.key<R[j].key)
     {    R[j+d]=R[j];
          j=j-d;
     }
     R[j+d]=tmp;
        }
        d=d/2;     //减小增量
    }
}

8.快速排序

void QuickSort(RecType R[],int s,int t) 
//对R[s]至R[t]的元素进行快速排序
{       int i=s,j=t;    RecType tmp;
        if (s<t)                     //区间内至少存在2个元素的情况
        {     tmp=R[s];           //用区间的第1个记录作为基准
               while (i!=j)          //两端交替向中间扫描,直至i=j为止
     {    while (j>i && R[j].key>=tmp.key)   j--;  
           R[i]=R[j];
                     while (i<j && R[i].key<=tmp.key)   i++;
           R[j]=R[i];
          }
                R[i]=tmp;
                QuickSort(R,s,i-1);    //对左区间递归排序
                QuickSort(R,i+1,t);   //对右区间递归排序
        } 
        //递归出口:不需要任何操作
}

9.选择排序

void SelectSort(RecType R[],int n)
{     int i,j,k;  RecType tmp;
      for (i=0;i<n-1;i++)        //做第i趟排序
       {      k=i;
    for (j=i+1;j<n;j++)  
           if (R[j].key<R[k].key)
            k=j; 
    if (k!=i)                   //R[i]R[k] 
    {     tmp=R[i];  R[i]=R[k];  R[k]=tmp;  }
      }
 }

10.堆排序

10.1:堆的筛选

void sift(RecType R[],int low,int high)     //调整堆的算法
{      int i=low, j=2*i;            //R[j]是R[i]的左孩子
       RecType tmp=R[i];
       while (j<=high) 
       {
             if (j<high && R[j].key<R[j+1].key) j++;
             if   (tmp.key<R[j].key)       //双亲小
             {      R[i]=R[j];         //将R[j]调整到双亲结点位置上
          i=j;               //修改i和j值,以便继续向下筛选
             j=2*i;
             }
            else break;                           //双亲大:不再调整
      }
      R[i]=tmp;
}

10.2:堆排序代码

void HeapSort(RecType R[],int n)
{     int i;  RecType tmp;
      for (i=n/2;i>=1;i--)     //循环建立初始堆
           sift(R,i,n); 
      for (i=n; i>=2; i--)    //进行n-1次循环,完成推排序
      {  
            temp=R[1];           //R[1]  R[i]
            R[1]=R[i];  R[i]=tmp;
            sift(R,1,i-1);       //筛选R[1]结点,得到i-1个结点的堆
      }
}

11.归并排序

void Merge(RecType R[],int low,int mid,int high) 
{      RecType *R1;
       int i=low, j=mid+1, k=0; 
              //k是R1的下标,i、j分别为第1、2段的下标
       R1=(RecType *)malloc((high-low+1)*sizeof(RecType));
       while (i<=mid && j<=high) 
           if (R[i].key<=R[j].key)      //将第1段中的记录放入R1中
           {     R1[k]=R[i];  i++;k++;   }
           else            //将第2段中的记录放入R1中
           {    R1[k]=R[j];  j++;k++;   }   
           while (i<=mid)         //将第1段余下部分复制到R1
          {      R1[k]=R[i];  i++;k++;   }
          while (j<=high)        //将第2段余下部分复制到R1
          {      R1[k]=R[j];  j++;k++;  }
          for (k=0,i=low;i<=high;k++,i++)     //将R1复制回R中
                 R[i]=R1[k];
          free(R1);
  } 
void MergePass(RecType R[],int length,int n)
{      int i;
       for (i=0;i+2*length-1<n;i=i+2*length)   //归并length长的两相邻子表     
             Merge(R,i,i+length-1,i+2*length-1);
       if (i+length-1<n)               //余下两个子表,后者长度小于length
            Merge(R,i,i+length-1,n-1);      //归并这两个子表
}

12.基数排序

void RadixSort(RecType1 *&p,int r,int d) 
//p为待排序序列链表指针,r为基数,d为关键字位数
{     RecType1 *head[MAXR], *tail[MAXR], *t;  //定义各链队的首尾指针
      int i, j, k;
      for (i=0;i<d;i--)               //从低位到高位做d趟排序
      {       for (j=0;j<r;j++)           //初始化各链队首、尾指针
          head[j]=tail[j]=NULL;

    while (p!=NULL)             //对于原链表中每个结点循环
    {     k=p->data[i]-'0';     //找第k个链队
          if (head[k]==NULL)     //进行分配,即采用尾插法建立单链表
          {    head[k]=p;  tail[k]=p;  }
                    else
          {    tail[k]->next=p;  tail[k]=p;   }
                    p=p->next;            //取下一个待排序的结点
    }
    k=1;        //k表示当前构造生成树的第几条边,初值为1
    j=0;        //E中边的下标,初值为0
    while (k<g.n)    //生成的边数小于n时循环
    { 
                    u1=E[j].u;v1=E[j].v;    //取一条边的头尾顶点
          sn1=vset[u1];
          sn2=vset[v1];        //分别得到两个顶点所属的集合编号
           if (sn1!=sn2)      //两顶点属于不同的集合
          {    printf("  (%d,%d):%d\n",u1,v1,E[j].w);
        k++;               //生成边数增1
        for (i=0;i<g.n;i++)      //两个集合统一编号
              if (vset[i]==sn2)     //集合编号为sn2的改为sn1
            vset[i]=sn1;
         }
         j++;               //扫描下一条边
            }
}

 

posted @ 2022-10-23 09:26  skywxp  阅读(559)  评论(0)    收藏  举报