数据结构必背代码
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++; //扫描下一条边 } }

浙公网安备 33010602011771号