《数据结构》严蔚敏与陈越伪代码总结
1 //陈 2 typedef struct LNode *List;3 struct LNode{4 int Data[MaxSize];//如果放多个元素,这个可改为指针,在初始化中指向数组 5 int Last;6 };7 //严8 typedef struct {9 ElemType *elem;//存储空间基地址 zt:上面用的数组,数组首地址跟指针一样的,但这里没声明大小,初始化时再声明
10 int length;
11 } SqList;
线性表-顺序表-定义
1 //陈 2 List MakeEmpty(){3 List PtrL;4 PtrL=(List)malloc(sizeof(struct LNode));5 PtrL->Last=-1;6 return PtrL;7 }8 //严 9 Status InitList(SqList &L){
10 L.elem=new ElemType[MAXSIZE];
11 if(!L.elem)exit(OVERFLOW); //多了校验分配失败
12 L.length=0;
13 return OK;
14 }
线性表-顺序表-初始化
1 //陈 2 int Find(int X,List PtrL){3 int i=0;4 while(i<=PtrL->Last&&PtrL->Data[i]!=X) i++;5 if(i>PtrL->Last) return -1;6 else return i;7 }8 //严 9 int LocateElem(SqList L,ElemType e){
10 for(i=0;i<L.length;i++){
11 if(e==L.elem[i]) return i+1; //查找成功返回序号
12 }
13 return 0;
14 }
15 //取值
16 //严 获取第i个值,他的数组存储位置是i-1
17 Status GetElem(SqlList &L,int i,ElemType &e){
18 if(i<1||i>L.length) return ERROR; //判断i值是否合理
19 e=L.elem[i-1];
20 return OK;
21 }
线性表-顺序表-查找
1 //陈 2 void insert(ElementType X,int i,List PtrL){3 //i表示插入第几个数,他在数组中的位置是i-1 4 int j; 5 if(PtrL->Last==MaxSize-1){6 printf("表满");7 return;8 }9 if(i<1||i>PtrL->Last+2){ //i最小是第1个数字;last初始值是-1,所以加2,严老师初始值是0,所以加1
10 printf("位置不合法");
11 return;
12 }
13 for(j=PtrL->Last;j>=i-1;j--)
14 PtrL->Data[j+1]=PtrL->Data[j];
15 PtrL->Data[i-1]=X;
16 PtrL->Last++;
17 return;
18 }
19 //严
20 Status ListInsert(SqList &L,int i,ElemType e) {
21 if(i<1||i>L.length+1) return ERROR; //插入位置不合理
22 if(L.length==MAXSIZE) return ERROR; //表满了
23 for(j=L.length-1;j>=i-1;j--) L.elem[j+1]=L.elem[j]; //后面元素向后移一位
24 L.elem[i-1]=e; //做插入
25 L.length++; //长度+1
26 return OK;
27 }
线性表-顺序表-插入
1 //陈 2 void Delete (int i,List PtrL){3 //i表示删除第几个数,他在数组中的位置是i-1 4 int j;5 if(i<1||i>PtrL->Last+1){ //删的位置不合理 6 printf("不存在");7 return; 8 }9 for(j=i;j<=PtrL->Last;j++) //元素往前移一位
10 PtrL->Data[j-1]=PtrL->Data[j];
11 PtrL->Last--;
12 }
13 //严
14 Status ListDelete(SqList &L,int i){
15 if(i<1||i>L.length) return ERROR; //删的位置不合理
16 for(j=i;j<=L.length-1;j++) L.elem[j-1]=L.elem[j];
17 L.length--;
18 return OK;
19 }
线性表-顺序表-删除
1 //陈2 typedef struct LNode *List;3 struct LNode{4 ElementType Data;5 List Next;6 };7 //严8 typedef struct LNode{9 ElemType data;
10 struct LNode *next;
11 } LNode,*LinkList; //LinkList为指向结构体LNode的指针类型
12
13 //附:陈,求表长
14 int length(List PtrL){
15 int j=0;
16 List p=PtrL;
17 while(p){
18 p=p->Next;
19 j++;
20 }
21 return j;
22 }
线性表-链表-定义
1 //严
2 Status InitList(LinkList &L){
3 L=new LNode; //生成新节点作为头结点,用头指针,指向头结点
4 L->next=NULL; //头结点的指针域置空
5 return OK;
6 }
线性表-链表-初始化
1 //陈 2 List findKth(int K,List PtrL){3 List p=PtrL;4 int i=1;5 while(i<K&&p!=NULL){6 p=p->Next;7 i++;8 }9 if(i==K)return p;
10 else return NULL;
11 }
12 //严
13 Status GetElem(LinkList L,int i,ElemType &e){
14 p=L.next; //p指向首元结点
15 j=1;
16 while(p&&j<i){ //找第i个元素
17 p=p->next;
18 ++j;
19 }
20 if(!p||j>i) return ERROR; //i>n或i<=0,i值不合法,比如i直接取-1,j=1比i大,i就不合法,若i>n,那取到边界外了,p早就为null了
21 e=p->data;
22 return OK;
23 }
线性表-链表-取值
1 //陈2 List find(Element X,List PtrL){3 List p=PtrL;4 while(p!=NULL&&p->Data!=X)p=p->Next;5 return p;6 }7 //严8 LNode *LocateElem(LinkList L,ElemType e){ //返回指向LNode类型的指针 9 p=L->next; //还是指向首元结点
10 while (p&&p->data!=e) p=p->next; //直到p为空或找到
11 return p;
12 }
线性表-链表-查找
1 //陈 2 List Insert(ElementType X,int i,List PtrL){3 List p,s;4 if(i==1){ //新节点插在表头 如果有头指针,就不用单独考虑这种了 5 s=(List)malloc(sizeof(struct LNode));6 s->Data=X;7 s->Next=PtrL;8 return s; 9 }
10 p=findKth(i-1,PtrL); //查找第i-1个结点
11 if(p==NULL){ //第i-1个结点不存在
12 return NULL;
13 }else{
14 s=(List)malloc(sizeof(struct LNode));
15 s->Data=X;
16 s->Next=p->Next;
17 p->Next=s; //新节点插到p结点后面
18 return PtrL;
19 }
20 }
21 //严
22 Status ListInsert(LinkList &L,int i,ElemType e){
23 p=L;j=0;
24 while(p&&j<i-1) { //找到第i-1个元素,并用p指向 ,有头结点,不用单独考虑插到第1位
25 p=p->next;
26 j++;
27 }
28 if(!p||j>i-1) return ERROR; //与上面获取值一样,校验不合法
29 s=new LNode;
30 s->data=e;
31 s-next=p-next;
32 p->next=s;
33 return OK;
34 }
线性表-链表-插入
1 //严2 //前插法3 void CreateList_H(LinkList &L,int n){4 L=new LNode;5 L->next=NULL; //建立带头结点的空链表 6 for(i=0;i<n;i++){ //逆序输入n个值,不断插到头部 7 p=new LNode;8 cin>>p->data; //给data设置值 9 p->next=L->next;
10 L->next=p; //头结点不断指向新的首元结点
11 }
12 }
13 //后插法
14 void CreateList_R(LinkList &L,int n){
15 L=new LNode;
16 L-next=NULL;
17 r=L; //r当做尾指针,指向头结点
18 for(i=0;i<n;++i){
19 p=new LNode;
20 cin>>p->data;
21 p->next=NULL;
22 r->next=p; //新结点p插到尾部
23 r=p; //尾指针指向尾部
24 }
25 }
线性表-链表-创建单链表的两种方法-前插法、后插法
1 //陈 2 List Delete(int i,List PtrL){3 List p,s; //s用来释放空间 ,p是要删除结点的前驱 4 if(i==1){ //删除第1个结点 5 s=PtrL; 6 if(PtrL!=NULL)PtrL=PtrL->Next;7 else return NULL;8 free(s);9 return PtrL;
10 }
11 p=findKth(i-1,PtrL);
12 if(p==NULL)return NULL; //要删除结点的前一个结点 不存在
13 else if(p->Next==NULL) return NULL; //前一个结点存在,但要删除的结点不存在
14 else{
15 s=p->Next; //删除第i个结点
16 p->Next=s->Next;
17 free(s);
18 return PtrL;
19 }
20 }
21 //严
22 Status ListDelete(LinkList &L,int i){
23 p=L; //p是被删结点的前驱
24 j=0;
25 while (!(p->next)&&j<i-1){
26 p=p->next;
27 j++;
28 }
29 if(p->next||j>i-1) return ERROR; //p-next为空了,或者i值不合法 则退出
30 q=p->next;
31 p->next=q->next;
32 delete q;
33 return OK;
34 }
线性表-链表-删除
1 //严2 //双向链表的定义3 typedef struct DuLNode{4 ElemType data;5 struct DuLNode *prior;6 struct DuLNode *next;7 } DuLNode ,*DuLinkList;8 9 //双向链表的插入
10 Status ListInsert_DuL(DuLinkList &L,int i,ElemType e){
11 //带头结点的双链表L,在第i个位置之前插入e
12 if(!(p=GetElem_DuL(L,i))) return ERROR; //找到第i个位置的元素p
13 s=new DuLNode;
14 s-data=e;
15 s-next=p;
16 s-prior=p->prior;
17 p->prior->next=s;
18 p->prior=s;
19 return OK;
20 }
21
22 //双向链表的删除
23 Status ListDelete_DuL(DuLinkList &L,int i){
24 //删除 带头结点的双链表L的第i个元素
25 if(!(p=GetElem_DuL(L,i))) return ERROR; //找到第i个位置的元素p
26 p->prior->next=p->next;
27 p->next->prior=p->prior;
28 delete p;
29 return OK;
30 }
线性表-链表-双向链表-定义、插入、删除
尾指向头,就是循环链表。
1 //陈 2 typedef struct SNode *Stack;3 struct SNode{4 ElementType Data[MaxSize];5 int Top;6 };7 //严8 typedef struct{9 SElemType *base; //栈底指针
10 SElemType *top; //栈顶指针
11 int stacksize; //栈可用的最大容量
12 } SqStack;
线性表-顺序栈-定义
1 //严
2 Status InitStack(SqStack &S){
3 S.base=new SElemType[MAXSIZE]; //为顺序栈,分配一个最大容量为MAXSIZE的数组空间
4 if(!S.base) exit(OVERFLOW); //分配失败
5 S.top=S.base; //top初始为base,空栈
6 S.stacksize=MAXSIZE; //stacksize置为数组最大容量
7 return OK;
8 }
线性表-顺序栈-初始化
1 //陈 2 void Push(Stack PtrS,ElementType item{3 if(PtrS->Top==MaxSize-1){4 printf("满");5 return;6 }7 PtrS->Data[++(PtrS->Top)]=item;8 return; 9 })
10 ElementType Pop(Stack PtrS){
11 if(PtrS->Top==-1)return ERROR;
12 return PtrS->Data[(PtrS->Top)--];
13 }
14 //严
15 Status Push(SqStack &S,SElemType e){
16 if(S.top-S.base==S.stacksize) return ERROR; //栈满
17 *S.top++=e; //e压入栈顶,栈顶指针加1
18 return OK;
19 }
20 Status Pop(SqStack &S,SElemType &e){
21 if(S.top==S.base) return ERROR; //栈空
22 e=*--S.top;
23 return OK;
24 }
25 //严,取栈顶元素
26 SElemType GetTop(SqStack S){
27 if(S.top!=S.base) //栈非空
28 return *(S.top-1); //不修改栈顶指针,返回栈顶元素值
29 }
线性表-顺序栈-入栈、出栈
1 //陈 2 struct DStack{3 ElementType Data[MaxSize];4 int Top1;5 int Top2;6 }; 7 void Push(struct DStack *PtrS,ElementType item,int Tag){8 if(PtrS->Top2-PtrS->Top1==1)return; //栈满 9 if(Tag==1) PtrS->Data[++(PtrS->Top1)]=item; //对第1个栈操作
10 else PtrS->Data[--(PtrS->Top2)]=item; //对第2个栈操作
11 }
12 ElementType Pop(struct DStack *PtrS,int Tag){
13 if(Tag==1){
14 if(PtrS->Top1==-1)return NULL; //第1个栈空
15 else return PtrS->Data[(PtrS->Top1)--];
16 }else{
17 if(PtrS->Top2==MaxSize))return NULL; //第2个栈空
18 else return PtrS->Data[(PtrS->Top2)++];
19 }
20 }
线性表-顺序栈-两头生长:定义、入栈、出栈
1 //陈 2 typedef struct SNode *Stack;3 struct SNode{4 ElementType Data;5 struct SNode *Next;6 };7 //严8 typedef struct StackNode{9 ElemType data;
10 struct StackNode *next;
11 } StackNode,*LinkStack;
线性表-链栈-定义
1 //陈 2 Stack CreateStack(){3 Stack S;4 S =(Stack)malloc(sizeof(struct SNode));5 S->Next=NULL;6 return S;7 }8 int isEmpty(Stack S){9 return (S->Next==NULL);
10 }
11 //严
12 Status InitStack(LinkStack &S){
13 S=NULL; //栈没必要设头结点,初始化直接置为空就行
14 return OK;
15 }
线性表-链栈-初始化
1 //陈 2 void Push(ElementType item,Stack S){3 struct SNode *TempCell;4 TempCell=(struct SNode *)malloc(sizeof(struct SNode));5 TempCell->Data=item; 6 TempCell->Next=S->Next;7 S->Next=TempCell;//S的位置是栈顶,他总是next指向最顶部的元素 新元素插到头结点S和首元结点S->next之间,像链表的头插法 8 }9 ElementType Pop(Stack S){
10 struct SNode *FirstCell; //用来释放空间
11 ElementType TopElement; //返回元素
12 if(isEmpty(S))return NULL;
13 else{
14 FirstCell=S->Next; //S->Next指向栈顶元素
15 S->Next=FirstCell->Next;
16 TopElement=FirstCell->Data;
17 free(FirstCell);
18 return TopElement;
19 }
20 }
21 //严
22 Status Push(LinkStack &S,SElemType e){
23 p=new StackNode;
24 p->data=e;
25 p->next=S; //因为没设头结点,所以新元素直接指向旧的栈顶元素
26 S=p; //把新元素作为栈顶
27 return OK;
28 }
29 Status Pop(LinkStack &S,SElemType e){ //删除S的栈顶元素,用e返回其值
30 if(S==NULL) return ERROR;
31 e=S->data;
32 p=S; //p临时保存栈顶元素空间,以备释放
33 S=S->next; //修改栈顶指针
34 delete p;
35 return OK;
36 }
37 //严 取栈顶元素
38 SElemType GetTop(LinkStack S){
39 if(S!=NULL) return S->data;
40 }
线性表-链栈-入栈、出栈
1 //定义2 //陈3 struct QNode{4 ElementType Data[MaxSize];5 int front;6 int rear;7 };8 typedef struct QNode *Queue;9 //严
10 typedef struct{
11 QElemType *base; //存储空间的基地址
12 int front; //头指针
13 int rear; //尾指针
14 } SqQueue;
线性表-顺序队列(就是循环队列)-定义
1 //初始化2 //严3 Status InitQueue(SqQueue &Q){4 Q.base=new QElemType[MAXQSIZE]; //指针指向新分配的数组基地址 5 if(!Q.base) return ERROR; //校验分配失败 6 Q.front=Q.rear=0; //头尾指针置为0,队列为空 7 return OK;8 } 9 //求队列长度
10 int QueueLength(SqQueue Q){
11 return (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
12 }
线性表-顺序队列(就是循环队列)-初始化
1 //入队、出队2 //陈 3 void Add(ElementType item,Queue PtrQ){4 if((PtrQ->rear+1)%MaxSize==PtrQ->front)return NULL; //校验队满 5 PtrQ->rear=(PtrQ->rear+1)%MaxSize; //队尾+1 6 PtrQ->Data[PtrQ->rear]=item;7 }8 ElementType Delete(Queue PtrQ){9 if(PtrQ->front==PtrQ->rear)return NULL; //校验队空
10 PtrQ->front=(PtrQ->front+1)%MaxSize; //队头+1
11 return PtrQ->Data[PtrQ->front];
12 }
13 //严
14 Status EnQueue(SqQueue &Q,QElemType e) {
15 if((Q.rear+1)%MAXSIZE==Q.front) return ERROR; //校验队满
16 Q.base[Q.rear]=e;
17 Q.rear=(Q.rear+1)%MAXSIZE; //队尾指针+1
18 return OK;
19 }
20 Status DeQueue(SqQueue &Q,QElemType &e){
21 if(Q.front==Q.rear) return ERROR; //校验队空
22 e=Q.base[Q.front];
23 Q.front=(Q.front+1)%MAXSIZE; //队头指针+1
24 return OK;
25 }
26 //取队头元素
27 QElemType GetHead(SqQueue Q){
28 if(Q.front!=Q.rear) return Q.base[Q.front];
29 }
线性表-顺序队列(就是循环队列)-入队、出队
1 //定义2 //陈 3 struct Node{4 ElementType Data;5 struct Node *Next;6 };7 struct QNode{8 struct Node *front;9 struct Node *rear;
10 };
11 typedef struct QNode *Queue;
12 //严
13 typedef struct QNode{
14 QElemType data;
15 struct QNode *next;
16 } QNode,*QueuePtr;
17 typedef struct {
18 QueuePtr front;
19 QueuePtr rear;
20 } LinkQueue;
线性表-链队-定义
1 //初始化
2 //严
3 Status InitQueue(LinkQueue &Q){
4 Q.front=Q.rear=new QNode; //生成新结点作为头结点,队头和队尾指针指向此结点
5 Q.front->next=NULL; //头结点的指针域置为空
6 return OK;
7 }
线性表-链队-初始化
1 //入队、出队2 //陈 3 ElementType Delete(Queue PtrQ){4 Queue FrontCell; //临时保存出队元素,以备释放 5 ElementType FrontElem; //保存出队元素的值 6 if(PtrQ->front==NULL)return NULL; //校验队列为空 7 FrontCell=PtrQ->front; 8 if(PtrQ->front==PtrQ->rear)PtrQ->front=PtrQ->rear=NULL; //若队列只有一个元素,删除后,队列置为空 9 else FrontElem=FrontCell->Data;
10
11 PtrQ->front=PtrQ->front->Next; //队头+1
12 free(FrontCell);
13 return FrontElem;
14 }
15 //严
16 Status EnQueue(LinkQueue &Q,QElemType e){
17 p=new QNode; //p是QueuePtr类型,c语言里可以省略强转,强制类型转换是为了兼容c++
18 p->data=e;
19 p->next=NULL;
20 Q->rear->next=p; //初始化时,队头队尾指向同一个,所以若是第一次入队,这里使Q->front->next也指向了p,p是首元结点,从第二次入队开始,就只是新元素不断加到尾部了
21 Q->rear=p; //队尾指针后移一位,就是队尾+1
22 return OK;
23 }
24 Status DeQueue(LinkQueue &Q,QElemType &e){
25 if(Q.front==Q.rear) return ERROR; //校验队列为空
26 p=Q.front->next; //临时保存出队元素,以备释放
27 e=p->data;
28 Q.front->next=p->next; //队头+1,若p是最后一个元素,p->next就是NULL,那 Q.front->next也是NULL了
29 if(Q.rear==p) Q.rear=Q.front; //校验p是否是最后一个元素,若是,尾指针像初始化时一样,重新指向头结点,若不加校验,队头一直指向头结点,但删了首元结点后,又不管队尾指针,队尾就不知道指向谁了
30 delete p;
31 return OK;
32 }
33 //严 取队头元素
34 SElemType GetHead(LinkQueue Q){
35 if(Q.front!=Q.rear) return Q.front->next->data; //若非空,返回头结点指向的首元结点的值
36 }
线性表-链队-入队、出队
1 //串也有顺序存储和链式存储,考虑到效率和算法方便,多采用顺序存储2 //严3 //串的定长顺序存储 4 #define MAXLEN 255 //串的最大长度 5 typedef struct {6 char ch[MAXLEN+1]; //0空置不用,所以长度+1 7 int length; //串的当前长度 8 } SString; 9 //串的堆式顺序存储
10 typedef struct {
11 char *ch; //按串长分配存储区,若空串则为NULL
12 int length; //串的当前长度
13 } HString;
线性表-串
1 //广义表2 //陈 3 typedef struct GNode *GList;4 struct GNode{5 int tag; //标志域:0表示结点是单元素,1表示结点是广义表 6 union{7 ElementType Data;8 GList SubList; //子表指针域SubList与单元素数据域Data复用,即共用存储空间 9 } URegion;
10 GList Next; //指向后继结点
11 };
12 //严
13 typedef enum{ATOM,LIST} ElemTag; //ATOM==0:原子 ; LIST==1:子表
14 typedef struct GLNode{
15 ElemTag tag; //公共部分,用于区分原子结点和表结点
16 union{ //原子结点和表结点的联合部分
17 AtomType atom; //atom是原子结点的值域, AtomType由用户定义
18 struct {struct GLNode *hp,*tp;} ptr; //ptr是表结点的指针域,ptr.hp和ptr.tp分别指向表头和表尾
19 };
20 } *GList; //广义表的头尾链表存储表示
线性表-广义表
1 //树用儿子-兄弟表示法,就成了二叉树2 //一般二叉树用顺序存储浪费空间,所以大都用链式存储3 //特殊的二叉树有完美或满二叉树、完全树 。完全树可以用顺序存储4 5 //二叉树顺序存储定义 6 //严7 #define MAXSIZE 100 //二叉树的最大结点数8 typedef TElemType SqBiTree[MAXSIZE]; //0号单元存根结点 9 SqBiTree bt;
10
11 //二叉树链式存储定义
12 //陈
13 typedef struct TreeNode *BinTree;
14 struct TreeNode{
15 ElementType Data;
16 BinTree Left;
17 BinTree Right;
18 };
19 //严
20 typedef struct BiTNode{
21 TElemType data; //结点数据域
22 struct BiTNode *lchild,*rchild; //左右孩子指针
23 } BiTNode,*BiTree;
24
树-二叉树链式存储、顺序存储-定义
1 //中序-左根右2 //递归 3 //陈 4 void InOrderTraversal(BinTree BT){5 if(BT){6 InOrderTraversal(BT->Left);7 printf("%d",BT->Data);8 InOrderTraversal(BT->Right);9 }
10 }
11 //严
12 void InOrderTraverse(BiTree T){
13 if(T){
14 InOrderTraverse(T->lchild); //中序遍历左子树
15 count<<T->data; //访问根结点
16 InOrderTraverse(T->rchild); //中序遍历右子树
17 }
18 }
19 //非递归
20 //陈
21 void InOrderTraversal(BinTree BT){
22 BinTree T=BT; //用T做操作,不改变原树
23 Stack S=CreateStack(); //创建并初始化一个栈,栈是为了回溯
24 while(T||!isEmpty(S)){ //树不空说明这个树结点还有子树未遍历,栈不空说明还有等待回溯的结点
25 while(T){ //一直向左,并把沿途结点压入栈
26 PUSH(S,T);
27 T=T->Left;
28 }
29 if(!isEmpty(S)){
30 T=POP(S); //结点出栈
31 printf("%d",T->Data);//打印或访问结点
32 T=T->Right;//转向右子树
33 }
34 }
35 }
36 //严
37 void InOrderTraverse(BiTree T){
38 InitStack(S); //创建栈,用来做回溯
39 p=T; //用p做操作,不改变原树
40 q=new BiTNode; //临时存放根结点数据
41 while(p||!StackEmpty(S)){ //跟陈越老师的一样
42 if(p){ //p非空
43 Push(S,p); //根指针入栈
44 p=p->lchild; //根指针已入栈,遍历左子树
45 }else{ //p空
46 Pop(S,q); //出栈
47 count<<q->data; //访问根结点
48 p=q->rchild; //遍历右子树
49 }
50 }
51 }
树-二叉树链式存储-中序遍历
1 //先序-根左右2 //陈3 void PreOrderTraversal(BinTree BT){4 if(BT){5 printf("%d",BT->Data);6 PreOrderTraversal(BT->Left);7 PreOrderTraversal(BT->Right);8 }9 }
10 //非递归
11 void PreOrderTraversal(BinTree BT){
12 BinTree T=BT;
13 Stack S=CreateStack();
14 while(T||!isEmpty(S)){
15 while(T){
16 printf("%d",T->Data); //只是访问根结点的代码位置变了
17 PUSH(S,T);
18 T=T->Left;
19 }
20 if(!isEmpty(S)){
21 T=POP(S);
22 T=T->Right;
23 }
24 }
25 }
树-二叉树链式存储-先序遍历
1 //后序-左右根2 //陈 3 void PostOrderTraversal(BinTree BT){4 if(BT){5 PostOrderTraversal(BT->Left);6 PostOrderTraversal(BT->Right);7 printf("%d",BT->Data);8 }9 }
10 //非递归
11 void PostOrderTraversal(BinTree BT){
12 BinTree T=BT;
13 Stack S=CreateStack();
14 while(T||!isEmpty(S)){
15 while(T){
16 PUSH(S,T);
17 T=T->Left;
18 }
19 if(!isEmpty(S)){
20 T=POP(S);
21 T=T->Right;
22 printf("%d",T->Data); //只是访问根结点的代码位置变了
23 }
24 }
25 }
树-二叉树链式存储-后序遍历
1 //层序用的不是栈,而是队列2 //陈 3 void LevelOrderTraversal(BinTree BT){4 Queue Q; //队列做回溯 5 BinTree T; //临时用来操作树 6 if(!BT)return; //校验是否为空树 7 Q=CreateQueue(MaxSize); //创建并初始化队列 8 Add(BT,Q); //最初是根节点入队 9 while(!IsEmpty(Q)){
10 T=Delete(Q);
11 printf("%d",T->Data); //访问根节点,下面将左右孩子入队。
12 if(T->Left)Add(T->Left,Q);
13 if(T->Right)Add(T->Right,Q);
14 //提示一下:父弹出时,左右儿子入队;左儿子弹出时,左边两个孙子入队,然后右儿子弹出,右边两个孙子入队;这样总能一层层地访问
15 }
16 }
树-二叉树链式存储-层序遍历
1 //二叉树的二叉线索存储
2 //严
3 typedef struct BiThrNode{
4 TElemType data;
5 struct BiThrNode *lchild,*rchild; //左右孩子指针
6 int LTag,RTag; //左右标志
7 }BiThrNode,*BiThrTree ;
树-二叉树链式存储-线索存储
1 //二叉排序树,也叫二叉搜索树、二叉查找树,比二叉树多了个条件,左小右大2 //定义3 //严4 typedef struct { 5 KeyType key; //关键字项 6 InfoType otherinfo; //其他数据项 7 }ElemType; //每个结点的数据域的类型 8 typedef struct BSTNode{ //二叉排序树的二叉链表存储表示 9 ElemType data; //每个结点的数据域包括关键字项和其他数据项
10 struct BSTNode *lchild,*rchild; //左右孩子指针
11 } BSTNode,*BSTree;
12
树-二叉树链式存储-二叉排序树-定义
1 //创建2 //严3 void CreatBST(BSTree &T){4 T=NULL; //将二叉排序树T初始化为空 5 cin>>e; //读输入的数据e 6 while(e.data!=ENDFLAG){ // ENDFLAG为自定义常量,作为输入结束标志 7 InsertBST(T,e); //将此结点插入到二叉排序树T中 8 cin>>e; //继续读输入的数据 9 }
10 }
树-二叉树链式存储-二叉排序树-初始化
1 //查找-递归 2 //严3 BSTree SearchBST(BSTree T,KeyType key){4 //在二叉排序树T中,查找关键字等于key的数据元素5 if((!T)||key==T->data.key) return T; //要么T查完了也没找到,此时T为空,返回空; 要么查找成功,返回该数据元素结点的指针6 else if (key<T->data.key) return SearchBST(T->lchild,key); //在左子树中继续查找7 else return SearchBST(T->rchild,key); //在右子树中继续查找 8 } 9 //陈
10 Position Find(ElementType X,BinTree BST){
11 if(!BST)return NULL;
12 if(X>BST->Data) return Find(X,BST->Right); // 在右子树继续查找
13 else if(X<BST->Data) return Find(X,BST->Left); //在左子树继续查找
14 else return BST; //查找成功
15 }
16
17 //查找-非递归
18 //陈
19 Position IteraFind(ElementType X,BinTree BST){
20 while(BST){
21 if(X>BST->Data)
22 BST=BST->Right;
23 else if(X<BST->Data)
24 BST=BST->Left;
25 else return BST;
26 }
27 return NULL;
28 }
29
30 //附加
31 //陈
32 //查找最小值,最小值在最左边,这个展示下递归方式实现
33 Position FindMin(BinTree BST){
34 if(!BST)return NULL;
35 else if(!BST->Left)
36 return BST; //找到最左叶结点返回
37 else
38 return FindMin(BST->Left); //沿左分支继续查找
39 }
40 //查找最大值,最大值在最右边,这个展示下循环方式实现 ,递归和循环都可以用
41 Position FindMax(BinTree BST){
42 if(BST)
43 while(BST->Right) BST=BST->Right; //沿右分支继续查找,直到最右叶结点
44 return BST;
45 }
树-二叉树链式存储-二叉排序树-查找
1 //插入2 //陈 3 BinTree Insert(ElementType X,BinTree BST){4 if(!BST){ //树为空,则生成新的 5 BST=malloc(sizeof(struct TreeNode));6 BST->Data=X;7 BST->Left=BST->Right=NULL;8 }else{ //开始找要插入元素的位置 9 if(X>BST->Data) BST->Right=Insert(X,BST->Right); //递归插入右子树
10 else if(X<BST->Data) BST->Left=Insert(X,BST->Left); //递归插入左子树
11 //否则就是X已存在,什么都不做
12 }
13 return BST;
14 }
15 //严
16 void InsertBST(BSTree &T,ElemType e){
17 if(!T){ //树为空,生成新的
18 S=new BSTNode;
19 S->data=e;
20 S->lchild=S->rchild=NULL;
21 T=S;
22 }else if(e.key<T->data.key) InsertBST(T->lchild,e); //插到左边
23 else if(e.key>T->data.key) InsertBST(T->rchild,e); //插到右边
24 }
树-二叉树链式存储-二叉排序树-插入
1 //删除 三种情况,叶结点、1个孩子、2个孩子2 //陈 3 //陈越是用递归实现的 4 BinTree Delete(ElementType X,BinTree BST){5 Position Temp;6 if(!BST); //要删除的元素未找到,不做处理或打印个提示 7 else if(X>BST->Data) BST->Right=Delete(X,BST->Right); //右子树递归删除 8 else if(X<BST->Data) BST->Left=Delete(X,BST->Left); //左子树递归删除 9 else //找到了要删除的结点
10 if(BST->Left&&BST->Right){ //被删除的结点有左右两个子结点
11 Temp=FindMin(BST->Right); //在右子树中,找到最小的元素,填充删除结点
12 BST->Data=Temp->Data;
13 BST->Right=Delete(BST->Data,BST->Right); //填充后,再删除右子树中那个最小元素
14 }else{ //被删除的结点有一个子结点、或没有子结点
15 Temp=BST; //临时存放待删结点,以备释放
16 if(!BST->Left) BST=BST->Right; //左孩子为空,右孩子填充上来
17 else if(!BST->Right) BST=BST->Left; //右孩子为空,左孩子填充上来
18 free(Temp); //无子结点,那直接释放就行
19 }
20 return BST;
21 }
22 //严
23 //严蔚敏是用循环实现的
24 void DeleteBST(BSTree &T,KeyType key){
25 p=T;f=NULL; //p用来临时操作树T,f表示被删结点的父节点
26 while(p){
27 if(key==p->data.key) break; //从根开始查被删结点key,找到就停止循环
28 f=p; //每次都存一下父节点
29 if(key<p->data.key) p=p->lchild; //小于就去左子树继续找,大于就去右子树继续找
30 else p=p->rchild;
31 }
32 if(!p) return; //最后没找到被删结点,退出 ,若找到了,分下面三种情况
33 if(p->lchild&&p->rchild){ // 1、被删除的结点有左右两个子结点
34 q=p; //q临时存放被删结点p
35 s=p->lchild; //s要成为p左子树的最大值
36 while(s->rchild){ //s一直往右走到头,找到最大值
37 q=s; //q临时存放最大值的父节点
38 s=s->rchild;
39 }
40 p->data=s->data; //把最大值s提拔上来,替代被删结点p的值,做善后工作
41 if(q!=p) q->rchild=s->lchild; //q!=p,说明上面循环走了,q改成s了,那q的右儿子s被提拔了,但s没有右儿子,只有左儿子,s的左儿子就顶上s的位置,哪怕它是null
42 else q->lchild=s->lchild;//若q==p,说明上面循环没走,q还是p,即p的左儿子s被直接提拔上来,s没有右儿子,原来指向s的指针现在指向s的左儿子,对p来讲,左孙成了左儿
43 delete s;//释放
44 return ; //处理完成,直接退出,这里是修改了p的值,但没有改链表关系,下面是改了链表关系,直接重置p节点指针
45 }else if(!p->rchild){ //2、被删除的结点右孩子为空,左孩子直接上位
46 q=p; //q临时存放被删结点p
47 p=p->lchild; //重置p节点指针
48 }else if(!p->lchild){ //3、被删除的结点左孩子为空,右孩子直接上位
49 q=p; //q临时存放被删结点p
50 p=p->rchild;//重置p节点指针
51 }
52 if(!f) T=p; //能走到这里,说明p节点已被重置。若f==NULL,说明第一个while没走,要删的是根节点,重置后得p作为新树根
53 else if(q==f->lchild) f->lchild=p; //被删结点是其父节点f的左孩子,左孩子重连为重置后得p
54 else f->rchild=p; //被删结点是其父节点f的右孩子,右孩子重连为重置后得p
55 delete q;//释放
56 }
树-二叉树链式存储-二叉排序树-删除
1 //堆,即优先队列,是特殊队列。取元素按优先级,而非进队顺序;使用完全二叉树结构,分为最大堆、最小堆2 3 //定义4 //陈 5 typedef struct HeapStruct *MaxHeap;6 struct HeapStruct{7 ElemetType *Elements; //数组空间 8 int Size; //堆的当前元素个数 9 int Capacity; //堆的最大容量
10 };
11 //创建
12 MaxHeap Create(int MaxSize){
13 MaxHeap H=malloc(sizeof(struct HeapStruct));
14 H->Elements=malloc((MaxSize+1)*sizeof(ElementType)); //申请容量为MaxSize的数组空间
15 H->Size=0;
16 H->Capacity=MaxSize;
17 H->Elements[0]=MaxData; //定义哨兵为大于堆中所有可能元素的值,便于以后更快操作
18 //把MaxData换成小于堆中所有元素的MinData,同样适用于创建最小堆
19 return H;
20 }
树-二叉树顺序存储-堆-定义、创建
1 //最大堆为例2 //插入3 void Insert(MaxHeap H,ElementType item){4 int i;5 if(IsFull(H))return; //最大堆已满,退出 6 i=++H->Size; //i指向插入后堆中最后一个元素的位置 7 for(;H->Elements[i/2]<item;i/=2) //H->Element[ 0 ] 是哨兵元素,它不小于堆中的最大元素,控制顺环结束。i最小为1 8 H->Elements[i]=H->Elements[i/2];//向下过滤结点,并在此过程中交换数据 9 H->Elements[i]=item; //将item插入
10 }
11
12 //删除
13 ElementType DeleteMax(MaxHeap H){
14 ElementType MaxData,Temp; //分别存堆顶元素,堆尾元素
15 int Parent,Child; //这两个值用来一层层向下过滤,保证每层左右较大子结点成为父节点
16 if(IsEmpty(H))return; //最大堆已空,退出
17 MaxData=H->Elements[1]; //取出堆顶
18 Temp=H->Elements[H->Size--]; //取出堆尾
19 for(Parent=1;Parent*2<=H->Size;Parent=Child){ //从第一层开始向下层走
20 Child=Parent*2; //child代表来到下一层,再次循环时,进入的是上次较大子树的下一层,2就到4,3就到6,到6就不用管4、5那些值,因为4、5拼爹没拼过6、7
21 if(Child!=H->Size&&(H->Elements[Child]<H->Elements[Child+1])) Child++; //child代表左右子结点的较大者
22 if(Temp>=H->Elements[Child]) break;//走到最后一个节点了,结束循环,跳出循环,在最后一步让堆尾元素提拔为父节点
23 else H->Elements[Parent]=H->Elements[Child];//还有子树,让当前子树的左右孩子较大值者提拔为父节点,继续下次循环,进入被提拔者的下一层,比较它左右子树较大者
24 }
25 H->Elements[Parent]=Temp;//独子直接当爹,或者小儿子放左边
26 return MaxData;
27 }
28 //通俗一点讲,就是让大儿子当爹,大孙子当大儿子,依次类推直到最后一个子树,
29 //如果最后一个树有俩儿子,左儿子大,去当爹,右儿子要放左边
30 //如果最后一个树有一儿子,那他直接当爹
31 //找个实际的例子模拟一遍就明白了
树-二叉树顺序存储-堆-插入、删除
1 //最优二叉树,也叫哈夫曼树。带权路径长度(WPL)最小的二叉树2 //定义3 //陈 链式存储 4 typedef struct TreeNode *HuffmanTree;5 struct TreeNode{6 int weight;7 HuffmanTree Left,Right;8 }; 9 //严 顺序存储
10 typedef struct {
11 int weight; //结点的权值
12 int parent,lchild,rchild;//结点的双亲、左右孩子下标
13 } HTNode,*HuffmanTree; //动态分配数组存储
树-二叉树顺序、链式存储-哈夫曼树-定义
1 //构造2 //陈 3 HuffmanTree Huffman(MinHeap H){//假设最小堆里的值就是权值,把最小堆改成哈夫曼树4 HuffmanTree T;5 int i;6 for(i=1;i<H->Size;i++){ //若3个值,做2次合并 7 T=malloc(sizeof(struct TreeNode)); 8 T->Left=DeleteMin(H); //从最小堆中删除一个节点,作为新T的左子结点 9 T->Right=DeleteMin(H); //从最小堆中删除一个节点,作为新T的右子结点
10 T->weight=T->Left->weight+T->Right->weight; //计算新权值
11 Insert(H,T); //将新T插入最小堆
12 }
13 T=DeleteMin(H);
14 return T;
15 }
16 //严
17 void CreateHuffmanTree(HuffmanTree &HT,int n){
18 if(n<=1) return ; //
19 m=2*n-1;
20 HT= new HTNode[m+1]; //申请2n个单元的数组空间,其中0号单元未用
21 for(i=1;i<=m;i++){ //从1到2n-1所有单元中的父节点、左孩子、右孩子,初始化为0
22 HT[i].parent=0;
23 HT[i].lchild=0;
24 HT[i].rchild=0;
25 }
26 for(i=1;i<=n;++i){ //输入前n个单元叶子节点的权值
27 cin>>HT[i].weight;
28 }//初始化完成
29 for(i=n+1;i<m;++i){ //m=2n-1,此循环是从1到n-1 ,将两个节点权值和,作为新节点权值存到数组n+1之后的单元中
30 Select(HT,i-1,s1,s2);//在已初始化的数组HT中,选择两个父节点为0且权值最小的结点,并返回他们在HT中的序号s1和s2
31 HT[s1].parent=i; //新节点存到n+1之后单元中
32 HT[s2].parent=i;
33 HT[i].lchild=s1; //记录新节点的左右儿子
34 HT[i].rchild=s2;
35 HT[i].weight=HT[s1].weight+HT[s2].weight; //记录新节点的权重值
36 }
37 }
树-二叉树顺序、链式存储-哈夫曼树-构造
1 //定义2 //严 3 //邻接矩阵存储,图没有顺序存储结构,但可以用二维数组表示元素之间关系4 5 #define MVNum 100 //最大顶点数 6 typedef char VerTexType; //假设顶点数据类型为字符型 7 typedef int ArcType; //假设边的权值类型为整型 8 typedef struct{9 VerTexType vexs[MVNum]; //顶点表,用一维数组存储
10 ArcType arcs[MVNum][MVNum]; //邻接矩阵,表示顶点间的关系,用二维数组表示
11 int vexnum,arcnum; //图的当前顶点数和边数
12 } AMGraph;
图-邻接矩阵表示-定义
1 //严2 #define MaxInt 32767 //表示极大值,即无穷 3 4 Status CreateUDN(AMGraph &G){ //用邻接矩阵表示法,创建无向图5 cin>>G.vexnum>>G.arcnum; //输入总顶点数、总边数 6 for(i=0;i<G.vexnum;++i) 7 cin>>G.vexs[i]; //按总顶点数,依次输入顶点信息 8 9 for(i=0;i<G.vexnum;++i)
10 for(j=0;j<G.vexnum;++j)
11 G.arcs[i][j]=MaxInt; //初始化邻接矩阵,边的权值均置为极大值MaxInt
12
13 for(k=0;k<G.arcnum;++k){ //按总边数,构造邻接矩阵
14 cin>>v1>>v2>>w; //输入一条边依附的顶点及权值
15 i=LocateVex(G,v1);
16 j=LocateVex(G,v2); //确定v1,v2在G中的位置,即顶点的数组下标
17 G.arcs[i][j]=w; //边<v1,v2>的权值置为w
18 G.arcs[j][i]=G.arcs[i][j]; //置<v1,v2>的对称边<v2,v1>的权值为w
19 }
20 return OK;
21 }
22 //陈
23 //无向图的邻接矩阵是对称的,可以只留上三角或下三角,用一维数组存储,数组下标是和=(i*(i+1)/2+j),数组值是权重——适合稠密图
图-邻接矩阵表示-创建
1 //定义 2 //严3 #define MVNum 100 //最大顶点数 4 typedef struct ArcNode{ //边结点 5 int adjvex; //该边所指向的顶点位置 6 struct ArcNode *nextarc; //指向下一条边的指针 7 OtherInfo info; //和边相关的信息 8 } ArcNode;9 typedef struct VNode{ //顶点信息
10 VerTexType data;
11 ArcNode * firstarc; //指向第一条依附该顶点的边的指针
12 } VNode,AdjList[MVNum]; // AdjList表示邻接表类型
13 typedef struct { //邻接表
14 AdjList vertices;
15 int vexnum,arcnum; //图的当前顶点数和边数
16 } ALGraph; //总之就是,邻接表里存放顶点数组,数组里每个顶点元素包含多条边的链式指针。
图-链式存储-邻接表-定义
1 //创建2 //严 3 Status CreateUDG(ALGraph &G){ // 用邻接表表示法,创建无向图 4 cin>>G.vexnum>>G.arcnum; //还是输入总顶点数、总边数 5 for(i=0;i<G.vexnum;++i){ 6 cin>>G.vertices[i].data; //还是按总顶点数,依次输入顶点信息 7 G.vertices[i].firstarc=NULL; //每个顶点的首条边初始化为null 8 }9 for(k=0;k<G.arcnum;++k){// 还是按总边数,构造邻接表
10 cin>>v1>>v2; //还是输入一条边依附的两个顶点
11 i=LocateVex(G,v1);
12 j=LocateVex(G,v2); //还是确定v1,v2在G中的位置,即顶点在G.vertices中的序号
13
14 p1=new ArcNode; //生成一个新的边结点*p1
15 p1->adjvex=j; //邻结点序号为j
16 p1->nextarc=G.vertices[i].firstarc;
17 G.vertices[i].firstarc=p1; //将新节点*p1插入顶点vi的边表头部
18
19 p2=new ArcNode; //生成另一个对称的新的边结点*p2
20 p2->adjvex=i; //邻接点序号为i
21 p2->nextarc=G.vertices[j].firstarc;
22 G.vertices[j].firstarc=p2; //将新节点*p2插入顶点vj的边表头部
23 }
24 return OK;
25 }
26 //陈:邻接表,用指针数组存储,只存非零 ——适合稀疏图
图-链式存储-邻接表-创建
图的链式存储有邻接表、十字链表、邻接多重表,后两种991大纲不考,不列代码。
1 //陈 2 void DFS(Vertex X){3 Visited(V)=true; // Vertex是顶点集合,E是边集合,V,W是一对顶点,(V,W)是一条边 4 for(V的每个邻接点W) 5 if(!Visited(W)) //若邻接点为空 6 DFS(W); 7 }8 //严9 //遍历连通图
10 bool visited[MVNum]; //访问标志数组,其初始值为false
11 void DFS(Graph G,int v){ //从第v个顶点出发,递归地深度优先遍历图G
12 cout<<v; //访问第v个顶点
13 visited[v]=true; //访问到就把它的标志数组值置为true
14 for(w=FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v,w)) //依次检查v的所有邻接点w, FirstAdjVex(G,v)表示v的第一个邻接点;NextAdjVex(G,v,w)表示v相对w的下一个邻接点,w>=0表示存在邻接点
15 if(!visited[w]) //若邻接点未访问
16 DFS(G,w); //对邻接点递归调用DFS
17 }
图-搜索-深度优先搜索DFS-连通图
1 //严
2 //遍历非连通图
3 void DFSTraverse(Graph G){
4 for(v=0;v<G.vexnum;++v)
5 visited[v]=false; //把标志数组初始化
6 for(v=0;v<G.vexnum;++v) //访问每个顶点
7 if(!visited[v]) //对未访问过的顶点,调用遍历连通图
8 DFS(G,v);
9 }
图-搜索-深度优先搜索DFS-非连通图
1 //严
2 //用邻接矩阵表示
3 void DFS_AM(AMGraph G,int v){ //图G为邻接矩阵类型,从第v个顶点出发,深度优先搜索遍历图G
4 cout<<v; //访问第v个顶点
5 visited[v]=true; //并把它的标志数组值置为true
6 for(w=0;w<G.vexnum;w++) //依次检查邻接矩阵中,顶点v所在的行
7 if(G.arcs[v][w]!=0&&!visited[w]) //G.arcs[v][w]!=0表示w是v的邻接点,如果w未访问,则递归调用DFS
8 DFS(G,w);
9 }
图-搜索-深度优先搜索DFS-邻接矩阵
1 //严 2 //用邻接表表示 3 void DFS_AL(ALGraph G,int v){ //图G为邻接矩阵类型,从第v个顶点出发,深度优先搜索遍历图G4 cout<<v; //访问第v个顶点5 visited[v]=true; //并把它的标志数组值置为true6 p=G.vertices[v].firstarc; //p指向v的边链表的第一个边结点 7 while(p!=NULL){ //边结点非空 8 w=p->adjvex; //w是v的邻接点 9 if(!visited[w])
10 DFS_AL(G,w); //若w未访问,则递归调用DFS_AL
11 p=p->nextarc; //p指向下一个边结点
12 }
13 }
图-搜索-深度优先搜索DFS-邻接表
1 //陈 2 void BFS(Vertex X){3 Visited(V)=true;4 Enqueue(V,Q); //把初始点放入队列5 while(!IsEmpty(Q)) {6 V=Dequeue(Q);7 for(V的每个邻接点W)8 if(!Visited(W)){9 Visited(W)=true;
10 Enqueue(W,Q); //把每个邻接点都放入队列,下次找邻接点的邻接点,一层层向外
11 }
12 }
13 }
14 //严
15 void BFS(Graph G,int v){ //按广度优先,非递归遍历连通图G
16 cout<<v; //访问第v个顶点
17 visited[v]=true; //并把它的标志数组值置为true
18 InitQueue(Q); //辅助队列Q初始化,置空
19 EnQueue(Q,v); //v进队
20 while(!QueueEmpty(Q)){ //队列非空
21 DeQueue(Q,u); //队头元素出队并置为u
22 for(w=FirstAdjVex(G,u);w>=0;w=NextAdjVex(G,u,w)) //依次检查u的所有邻接点w, FirstAdjVex(G,u)表示u的第一个邻接点;NextAdjVex(G,u,w)表示u相对w的下一个邻接点,w>=0表示存在邻接点
23 if(!visited[w]){ //w为u的尚未访问的邻接顶点
24 cout<<w; //访问w
25 visited[w]=true; //把它的标志数组值置为true
26 EnQueue[Q,w]; //w进队
27 }
28 }
29 }
图-搜索-广度优先搜索BFS-连通图
1 //最小生成树 MST Minimum Spanning Tree ,就是权重之和最小的,连通各顶点边,组成的集合。2 //思路是每一步都是当前最优的解,但不能保证总体是最优的。这叫贪心算法3 4 //Prim 从起点开始,不断找连通起点的,权重最小的边,和它对应的顶点,加入集合,直到所有的顶点都加进来5 //陈 6 void Prim(){7 MST={s};8 while(1){9 V=未收录顶点中dist最小值;
10 if(这样的V不存在)break; //说明全搞完了
11 将V收录进MST:dist[V]=0;
12 for(V的每个邻接点W){
13 if(dist[W]!=0){
14 if(E(V,W)<dist[W]){
15 dist[W]=E(V,W);
16 parent[W]=V;
17 }
18 }
19 }
20 }
21 if(MST中收录的顶点不足V个) Error;
22 }
23
24 //严
25 struct { //定义辅助数组,用来记录从顶点集U到V-U的权值最小的边
26 VerTexType adjvex; //最小边在U中的那个顶点
27 ArcType lowcost; //最小边上的权值
28 } closedge[MVNum];
29
30 //无向网G以邻接矩阵形式存储,从顶点u出发构造G的最小生成树T,输出T的各条边
31 void MiniSpanTree_Prim(AMGraph G,VerTexType u){
32 k=LocateVex(G,u); //k为顶点u的下标
33 for(j=0;j<G.vexnum;++j) //对V-U的每一个顶点vj,初始化closedge[j]
34 if(j!=k)
35 closedge[j]={u,G.arcs[k][j]} //{adjvex,lowcost}
36 closedge[k].lowcost=0; //初始,U={u}
37 for(i=1;i<G.vexnum;++i){ //选择其余n-1个顶点,生成n-1条边(n=G.vexnum)
38 k=Min(closedge); //求出T的下一个结点:第k个顶点,closedge[k]中存有当前最小边
39 u0=closedge[k].adjvex; //u0为最小边的一个顶点,u0∈U
40 v0=G.vexs[k]; //v0为最小边的另一个顶点,v0∈V-U
41 cout<<u0<<v0; //输出当前的最小边(u0,v0)
42 closedge[k].lowcost=0; //第k个顶点并入U集
43 for(j=0;j<G.vexnum;++j)
44 if(G.arcs[k][j]<closedge[j].lowcost) //新顶点并入U后重新选择最小边
45 closedge[j]={G.vexs[k],G.arcs[k][j]};
46 }
47 }
图-应用-最小生成树-Prim
1 // Kruskal 将边按权值大小添加到图中,别形成环,直到所有顶点都连通2 //陈 3 void Kruskal(Graph G){4 MST={};5 while(MST中不到V-1条边&&E中还有边){6 从E中取一条权重最小的边E(V,W); //最小堆7 将E(V,W)从E中删除;8 if(E(V,W)不在MST中构成回路){9 将E(V,W)加入MST;
10 } else{
11 彻底无视E(V,W);
12 }
13 }
14 if (MST中不到V-1条边) Error;
15 }
16
17 //严
18 struct { //定义辅助数组,存储边的信息,包括边的两个顶点信息和权值
19 VerTexType Head; //边的始点
20 VerTexType Tail; //边的终点
21 ArcType lowcost; //边上的权值
22 } Edge[arcnum];
23 int Vexset[MVNum]; //表示该顶点所在的连通分量
24
25 void MiniSpanTree_Kruskal(AMGraph G){
26 //无向网G以邻接矩阵形式存储,构造G的最小生成树T,输出T的各条边
27 Sort(Edge); //将数组Edge中的元素按权值从小到大排序
28 for(i=0;i<G.vexnum;++i) Vexset[i]=i;//辅助数组,表示各顶点自成一个连通分量
29 for(i=0;i<G.arcnum;++i){ //依次查看数组Edge中的边
30 v1=LocateVex(G,Edge[i].Head); //v1为边的始点Head的下标
31 v2=LocateVex(G,Edge[i].Tail); //v2为边的终点Tail的下标
32 vs1=Vexset[v1]; //获取边Edge[i]的始点所在的连通分量vs1
33 vs2=Vexset[v2]; //获取边Edge[i]的终点所在的连通分量vs2
34 if(vs1!=vs2){ //边的两个顶点分属不同的连通分量
35 cout<<Edge[i].Head<<Edge[i].Tail; //输出此边
36 for(j=0;j<G.vexnum;++j) //合并vs1和vs2两个分量,即两个集合统一编号
37 if(Vexset[j]==vs2) Vexset[j]=vs1; //集合编号为vs2的都改成vs1
38 }
39 }
40 }
图-应用-最小生成树-Kruskal
1 //最短路径问题2 //单源-无权-BFS3 //单源-有权-BFS-Dijkstra算法 4 //数组下标代表各点,值为源点到当前点最短权重值,数组中找最小,然后添加点到T,找出度该改值就改;再找没找过的最小,…… 5 //上面博客的理解,跟下面老师的逻辑是一样的 6 7 //陈 8 void Dijkstra(Vertex s){9 while(1){
10 V=未收录顶点中dist最小者;
11 if(这样的V不存在) break; //说明所有点都搞完了
12 collected[V]=true;//处理点
13 for(V的每个邻接点W)
14 if(collected[W]==false) //这个点没被处理过
15 if(dist[V]+E<v,w><dist[W]){ //源点到这里的权值跟目前数组的值比是不是小
16 dist[W]=dist[V]+ E<v,w>; //是就改值
17 path[W]=V;
18 }
19 }
20 }
21
22 //严
23 void ShortestPath_DIJ(AMGraph G,int v0){
24 //用 Dijkstra 算法求有向网G的v0顶点到其余顶点的最短路径
25 n=G.vexnum; //n为G中顶点的个数
26 for(v=0;v<n;++v){ //n个顶点依次初始化
27 S[v]=false; //S初始为空集
28 D[v]=G.arcs[v0][v]; //将v0到各个终点的最短路径长度初始化为弧上的权值
29 if(D[v]<MaxInt) Path[v]=v0; //如果v0和v之间有弧,则将v的前驱置为v0
30 else Path[v]=-1; //如果v0和v之间无弧,则将v的前驱置为-1
31 }
32 S[v0]=true; //将v0加入S
33 D[v0]=0; //源点到源点的距离为0
34 //初始化结束,开始主循环,每次求得v0到某个顶点v的最短路径,将v加到S集
35 for(i=1;i<n;++i){ //对其余n-1个顶点,依次进行计算
36 min=MaxInt;
37 for(w=0;w<n;++w)
38 if(!S[w]&&D[w]<min){
39 v=w;
40 min=D[w]; //选择一条当前的最短路径,终点为v
41 }
42 S[v]=true; //将v加入S
43 for(w=0;w<n;++w){ //更新从v0出发到集合V-S上所有顶点的最短路径长度
44 if(!S[w]&&(D[v]+G.arcs[v][w]<D[w])){
45 D[w]=D[v]+G.arcs[v][w];//更新D[w]
46 Path[w]=v; //更新w的前驱为v
47 }
48 }
49 }
50 }
图-应用-最短路径-Dijkstra
1 //多源-Floyd算法 S矩阵存两点权重距离,P矩阵存他们过哪个点连在一起的,S矩阵和P矩阵都是延对角线对称,因此只看一半就行 2 //”a[i][j]的距离” > “a[i][0]+a[0][j]”(a[i][0]+a[0][j]表示”i与j之间经过第1个顶点的距离”)3 //意思是 这两点现在的距离,如果过 第一个点0的距离比现有距离更短,那就把更短距离更新进S矩阵,然后把他们经过的这个点0,写进P矩阵 4 //陈 5 void Floyd(){6 for(i=0;i<N;i++)7 for(j=0;j<N;j++){8 D[i][j]=P[i][j];9 path[i][j]=-1;
10 }
11 for(k=0;k<N;k++)
12 for(i=0;i<N;i++)
13 for(j=0;i<N;i++)
14 if(D[i][k]+D[k][j]<D[i][j]){
15 D[i][j]=D[i][k]+D[k][j];
16 path[i][j]=k;
17 }
18 }
19 //严
20 void ShortestPath_Floyd(AMGraph G){
21 //用Floyd算法求有向网G中各对顶点i和j之间的最短路径
22 for(i=0;i<G.vexnum;++i) //各对结点之间初始已知路径及距离
23 for(j=0;j<G.vexnum;++j){
24 D[i][j]=G.arcs[i][j];
25 if(D[i][j<MaxInt]) Path[i][j]=i;//如果i和j之间有弧,则将j的前驱置为i
26 else Path[i][j]=-1; //如果i和j之间无弧,则将j的前驱置为-1
27 }
28 for(k=0;k<G.vexnum;++k)
29 for(i=0;i<G.vexnum;++i)
30 for(j=0;j<G.vexnum;++j)
31 if(D[i][k]+D[k][j]<D[i][j]){//从i经k到j的一条路径更短
32 D[i][j]=D[i][k]+D[k][j];//更新 D[i][j]
33 Path[i][j]=Path[k][j]; //更改j的前驱为k
34 }
35 }
图-应用-最短路径-Floyd
1 //有向无环图 Directed Acyclic Graph简称DAG,有方向的,没有首尾相连的图2 //AOV网,顶点活动网(Activity On Vertex network),顶点表示活动、边表示活动间先后关系的有向图 3 //AOV是DAG, 首尾相连就没有起点了,也没有顺序,且会死循环 4 //AOV中所有活动组成线性序列,叫做拓扑序列Topological order,5 //由AOV构造 拓扑序列的过程叫做拓扑排序Topological sort6 //两种算法可实现拓扑排序 7 8 //陈 9 //Kahn算法 有向图中选个没有前驱的顶点,删除他和他的所有边,放入栈,重复此步骤直到所有顶点入栈,栈中就是个线性序列
10 void TopSort(){
11 for(cnt=0;cnt<V;cnt++){
12 V=未输出的,入度为0的顶点;
13 if(这样的V不存在){
14 图中有回路;
15 break;
16 }
17 输出V,或者记录V的输出序号;
18 for(V的每个邻接点W) Indegree[W]--;
19 }
20 }
21 //基于DFS的拓扑排序算法 它每次都沿着一条路径一直往下搜索,知道某个顶点没有了出度时,就停止递归,往回走
22 //此算法可以用来检测有向图是否DAG
23 void TopSort(){
24 for(图中每个顶点V)
25 if(Indegree[V]==0) Enqueue(V,Q); //随时将入度变为0的顶点放入一个容器
26 while(!isEmpty(Q)){
27 V=Dequeue(Q);
28 输出V,或者记录V的输出序号; cnt++
29 for(V的每个邻接点W){
30 if(--Indegree[W]==0) Enqueue(W,Q);//入度为0的放入容器
31 }
32 if(cnt!=V) Error(图中有回路);
33 }
34
35 //严
36 Status TopologicalSort(ALGraph G,int topo[]){
37 //有向图G采用邻接表存储结构
38 //若G无回路,则生成G的一个拓扑序列topo[]并返回OK,否则ERROR
39 FindInDegree(G,indegree); //求出各顶点的入度存入数组indegree中
40 InitStack(S); //栈S初始化为空
41 for(i=0;i<G.vexnum;++i)
42 if(!indegree[i]) Push(S,i); //入度为0者进栈
43 m=0; //对输出顶点计数,初始为0
44 while(!StackEmpty(S)){ //栈S非空
45 Pop(S,i); //将栈顶顶点vi出栈
46 topo[m]=i; //将vi保存在拓扑序列数组topo中
47 ++m; //对输出顶点计数
48 p=G.vertices[i].firstarc; //p指向vi的第一个邻接点
49 while(p!=NULL){
50 k=p->adjvex; //vk为vi的邻接点
51 --indegree[k]; //vi的每个邻接点的入度减1
52 if(indegree[k]==0) Push(S,k); //若入度减为0,则入栈
53 p=p->nextarc; //p指向顶点vi下一个邻接结点
54 }
55 }
56 if(m<G.vexnum) return ERROR; //该有向图有回路
57 else return OK;
58 }
图-应用-拓扑排序AOV
1 //关键路径 AOE-网(Activity On Edge) 2 //与AOV-网对应,它是以边表示活动的网。带权的有向无环图。3 //顶点表示事件,弧表示活动,权表示活动持续的时间。通常用来估算工程的完成时间4 5 //严6 Status CriticalPath(ALGraph G)7 {//G为邻接表存储的有向网,输出G的各项关键活动 8 if(!TopologicalOrder(G,topo)) return ERROR; 9 //调用拓扑排序算法,使拓扑序列保存在topo中,若调用失败,则存在有向环,返回ERROR
10 n=G.vexnum; //n为顶点个数
11 for(i=0;i<n;i++) //给每个事件的最早发生时间置初值0
12 ve[i]=0;
13 /*- - - - - - - - - - - 按拓扑次序求每个事件的最早发生时间 - - - - - - - - - -*/
14 for(i=0;i<n;i++)
15 {
16 k=topo[i]; //取得拓扑序列中的顶点序号k
17 p=G.vertices[k].firstarc; //p指向k的第一个邻接顶点
18 while(p!=NULL)
19 { //依次更新k的所有邻接顶点的最早发生时间
20 j=p->adjvex; //j为邻接顶点的序号
21 if(ve[j]<ve[k]+p->weight) //更新顶点j的最早发生时间ve[j]
22 ve[j]=ve[k]+p->weight;
23 p=p->nextarc; //p指向k的下一个邻接顶点
24 } //while
25 } //for
26 for(i=0;i<n;i++) //给每个事件的最迟发生时间置初值ve[n-1]
27 vl[i]=ve[n-1];
28 /*- - - - - - - - - - - - -按逆拓扑次序求每个事件的最迟发生时间- -- - - - - - - - - - - -*/
29 for(i=n-1;i>=0;i--)
30 {
31 k=topo[i]; //取得拓扑序列中的顶点序号k
32 p=G.vertices[k].firstarc; //p指向k的第一个邻接顶点
33 while(p!=NULL) //根据k的邻接点,更新k的最迟发生时间
34 {
35 j=p->adjvex; //j为邻接顶点的序号
36 if(vl[k]>vl[j]-p->weight) //更新顶点k的最迟发生时间vl[k]
37 vl[k]=vl[j]-p->weight;
38 p=p->nextarc; //p指向k的下一个邻接顶点
39 } //while
40 } //for
41 /*- - - - - - - - - - - - - -- -判断每一活动是否为关键活动- -- - - - - - - - - - - -*/
42 for(i=0;i<n;i++) //每次循环针对vi为活动开始点的所有活动
43 {
44 p=G.vertices[i].firstarc; //p指向i的第一个邻接顶点
45 while(p!=NULL)
46 {
47 j=p->adjvex; //j为i的邻接顶点的序号
48 e=ve[i]; //计算活动<vi, vj>的最早开始时间
49 l=vl[j]-p->weight; //计算活动<vi, vj>的最迟开始时间
50 if(e==l) //若为关键活动,则输出<vi, vj>
51 cout<<G.vertices[i].data <<G.vertices[j].data;
52 p=p->nextarc; //p指向i的下一个邻接顶点
53 } //while
54 } //for
55 }
图-应用-拓扑排序AOE
1 //严 2 //数据元素类型定义3 typedef struct{4 KeyType key; //关键字域 5 InfoType otherinfo; //其他域 6 }ElemType; 7 //顺序表定义8 typedef struct {9 ElemType *R; //存储空间基地址
10 int length; //当前长度
11 } SSTable;
12
13
14 //顺序查找
15 //严
16 int Search_Seq(SSTable ST,KeyType key){ //在顺序表ST中查找其关键字等于key的数据元素。若找到,返回该元素在表中的位置
17 for(i=ST.length;i>1;--i)
18 if(ST.R[i].key==key) return i; //从后往前找
19 return 0;
20 }
21 //设置监视哨的顺序查找
22 int Search_Seq(SSTable ST,KeyType key){ //找不到还是返回0,少了一次比较,length大于1000时,查找平均时间少了一半
23 ST.R[0].key=key; //哨兵
24 for(i=ST.length;ST.R[i].key!=key;--i);//从后往前找
25 return i;
26 }
查找-线性表-顺序查找
1 //陈 2 int BinarySearch(StaticTable *Tbl,ElementType K){3 int left,right,mid,notFound=-1;4 left=1; //初始左边界 5 right=Tbl->length; //初始右边界 6 while(left<right){7 mid=(left+right)/2; //计算中间元素坐标 8 if(K>Tbl->Element[mid])left=mid+1; //调整左边界 9 else if(K<Tbl->Element[mid])right=mid-1;//调整右边界
10 else return mid; //查找成功,返回数组元素下标
11 }
12 return notFound; //查找不成功,返回-1
13 }
14 //严
15 int Search_Bin(SSTable ST,KeyType key){
16 low=1;
17 high=ST.length; //置查找区间初值
18 while(low<=high){
19 mid=(low+high)/2;
20 if(key==ST.R[mid].key) return mid; //找到待查元素
21 else if(key<ST.R[mid].key) high=mid-1; //继续在前一子表查找
22 else low=mid+1; //继续在后一子表查找
23 }
24 return 0; //表中不存在待查元素
25 }
查找-线性表-折半查找
1 //严2 #define m 3 //B树的阶,暂设为3阶 3 typedef struct BTNode{4 int keynum; //结点中关键字的个数,即结点的大小 5 struct BTNode *parent;//指向双亲结点 6 KeyType K[m+1]; //关键字向量,0号单元未用 7 struct BTNode *ptr[m+1];//子树指针向量 8 Record *recptr[m+1]; //记录指针向量,0号单元未用 9 } BTNode,*BTree; //B树结点和B树的类型
10
11 typedef struct {
12 BTNode *pt; //指向找到的结点
13 int i; //1..m,在结点中的关键字序号
14 int tag; //1:查找成功;0:查找失败
15 } Result; //B树的查找结果类型
查找-树表(文件)-B树-定义
1 //严2 Result SearchBTree(BTree T,KeyType key){3 //在m阶B树上查找关键字key,返回Result类型结果4 //若查找成功,则特征值tag=1,指针pt所指结点中,第i个关键字等于key5 //否则特征值tag=0,等于key的关键字应插入指针pt所指结点中第i个和第i+1个关键字之间6 p=T;7 q=NULL;8 found=FALSE;9 i=0; //初始化,p指向待查结点,q指向p的双亲
10 while(p&&!found){
11 i=Search(p,key); //在p-key[1..keynum]中查找i,使得 p->key[i] <= k < p->key[i+1]
12 if(i>0&&p->key[i]==k) found=TRUE; //找到待查关键字
13 else {
14 q=p;
15 p=p->ptr[i];
16 }
17 }
18 if(found) return (p,i,1); //查找成功
19 else return (q,i,0); //查找不成功,返回K的插入位置信息
20 }
查找-树表(文件)-B树-查找
1 //严2 Status InsertBTree(BTree &T,KeyType K,BTree q,int i){3 //在m阶B树T上结点*q的key[i]与key[i+1]之间插入关键字K4 //若引起结点过大,则沿双亲链进行必要的分裂调整,使T仍是m阶B树5 x=K;6 ap=NULL;7 finished=FALSE; //x表示新插入的关键字,ap为一个空指针 8 while(q&&!=finished){9 Insert(q,i,x,ap); //将x和ap分别插入到q->key[i+1]和q->ptr[i+1]
10 if(q->keynum<m) finished=TRUE; //插入完成
11 else{ //分裂结点*p
12 s=[m/2];
13 split(q,s,ap);
14 x=q->key[s]; //将q->key[s+1..m],q->ptr[s..m]和q->recptr[s+1..m]移入新结点*ap
15 q=q->parent;
16 if(q) i=Search(q,x); //在双亲结点*q中查找x的插入位置
17 }
18 }
19 if(!finished) //T是空树(参数q初值为NULL)或者根结点已分裂为结点*q和*ap
20 NewRoot(T,q,x,ap); //生成含信息(T,x,ap)的新的根结点*T,原T和ap为子树指针
21 return OK;
22 }
查找-树表(文件)-B树-插入
1 //陈2 //定义 3 typedef struct HashTbl *HashTable;4 struct HashTbl{5 int TableSize;6 Cell *TheCells;7 }H ;8 //初始化 9 HashTable InitializeTable( int TableSize )
10 {
11 HashTable H;
12 int i;
13 if ( TableSize < MinTableSize ){
14 Error( "散列表太小" );
15 return NULL;
16 }
17 /* 分配散列表 */
18 H = (HashTable)malloc( sizeof( struct HashTbl ) );
19 if ( H == NULL )
20 FatalError( "空间溢出!!!" );
21 H->TableSize = NextPrime( TableSize );
22 /* 分配散列表 Cells */
23 H->TheCells=(Cell *)malloc(sizeof( Cell )*H->TableSize);
24 if( H->TheCells == NULL )
25 FatalError( "空间溢出!!!" );
26 for( i = 0; i < H->TableSize; i++ )
27 H->TheCells[ i ].Info = Empty;
28 return H;
29 }
查找-散列函数-冲突解决方法-开放地址法-平方探测法-定义、初始化
1 Position Find( ElementType Key, HashTable H ) /*平方探测*/2 { 3 Position CurrentPos, NewPos;4 int CNum; /* 记录冲突次数 */5 CNum = 0;6 NewPos = CurrentPos = Hash( Key, H->TableSize );7 while( H->TheCells[ NewPos ].Info != Empty &&H->TheCells[ NewPos ].Element != Key ) {8 /* 字符串类型的关键词需要 strcmp 函数!! */9 if(++CNum % 2){ /* 判断冲突的奇偶次 */
10 NewPos = CurrentPos + (CNum+1)/2*(CNum+1)/2;
11 while( NewPos >= H->TableSize )
12 NewPos -= H->TableSize;
13 } else {
14 NewPos = CurrentPos - CNum/2 * CNum/2;
15 while( NewPos < 0 )
16 NewPos += H->TableSize;
17 }
18 }
19 return NewPos;
20 }
查找-散列函数-冲突解决方法-开放地址法-平方探测法-查找
1 //陈2 void Insert( ElementType Key, HashTable H )3 { /* 插入操作 */4 Position Pos;5 Pos = Find( Key, H );6 if( H->TheCells[ Pos ].Info != Legitimate ) {7 /* 确认在此插入 */8 H->TheCells[ Pos ].Info = Legitimate;9 H->TheCells[ Pos ].Element = Key;
10 /*字符串类型的关键词需要 strcpy 函数!! */
11 }
12 }
查找-散列函数-冲突解决方法-开放地址法-平方探测法-插入
1 //严2 //- - - - -开放地址法散列表的存储表示- - - - -3 #define m 20 //散列表的表长4 typedef struct{5 KeyType key; //关键字项6 InfoType otherinfo; //其他数据项7 }HashTable[m];8 9 //查找
10 #define NULLKEY 0 //单元为空的标记
11 int SearchHash(HashTable HT,KeyType key)
12 {//在散列表HT中查找关键字为key的元素,若查找成功,返回散列表的单元标号,否则返回-1
13 H0=H(key); //根据散列函数H(key)计算散列地址
14 if(HT[H0].key==NULLKEY) return -1; //若单元H0为空,则所查元素不存在
15 else if(HT[H0].key==key) return H0; //若单元H0中元素的关键字为key,则查找成功
16 else
17 {
18 for(i=1;i<m;++i)
19 {
20 Hi=(H0+i)%m; //按照线性探测法计算下一个散列地址Hi
21 if(HT[Hi].key==NULLKEY) return -1; //若单元Hi为空,则所查元素不存在
22 else if(HT[Hi].key==key) return Hi; //若单元Hi中元素的关键字为key,则查找成功
23 } //for
24 return -1;
25 } //else
26 }
查找-散列函数-冲突解决方法-开放地址法-线性探测法-定义、查找
1 //陈 2 //将相应位置上冲突的所有关键词存储在同一个单链表中3 //定义 4 typedef struct ListNode *Position,*List;5 struct ListNode{6 ElementType Element;7 Position Next;8 };9 typedef struct HashTbl *HashTable;
10 struct HashTbl{
11 int TableSize;
12 List TheLists;
13 };
14 //查找
15 Position Find(ElementType X,HashTable H){
16 Position P;
17 int Pos;
18 Pos=Hash(X,H->TableSize);
19 P=H->TheLists[Pos].Next;
20 if(P!=NULL&&strcmp(P->Element,X)) P=P->Next;
21 return P;
22 }
查找-散列函数-冲突解决方法-链地址法-分离地址法-定义、查找
int ar[5]={3,8,9,5,2};//对它从小到大排序
1 //插入排序, 每个数与前面排好序的比较,满足条件,就把大家往后移,当前数插入前面自己的位置 2 //3,8,9,5,2 3 //arr[1]是8,temp= arr[1] ,arr[0]没有>arr[1], 4 //arr[2]是9,temp= arr[2] ,5 //arr[3]是5,temp= arr[3] ,6 //arr[4]是2,temp= arr[3] ,7 //第1轮 3 8 9 5 2 8 //第2轮 3 8 9 5 29 //第3轮 3 5 8 9 2
10 //第4轮 2 3 5 8 9
11 void insert_sort(int arr[], int len){
12 int i,j,temp;
13 for (i=1;i<len;i++){ //此处不-1,因为是从1开始
14 temp = arr[i]; //当前数待插入,先拿出来
15 for (j=i;j>0 && arr[j-1]>temp;j--) //循环每个数,把它和前面比,满足条件就把前面的往后挪一位,再比前面的,
16 arr[j] = arr[j-1];
17 arr[j] = temp; //直到没法挪,当前位置前一位不满足大小,就把待插入的放到当前位
18 }
19 }
20 //严
21 void InsertSort(SqList &L)
22 {//对顺序表L做直接插入排序
23 for(i=2;i<=L.length;++i)
24 if(L.r[i].key<L.r[i-1].key) //“<”,需将r[i]插入有序子表
25 {
26 L.r[0]=L.r[i]; //将待插入的记录暂存到监视哨中
27 L.r[i]=L.r[i-1]; //r[i-1]后移
28 for(j=i-2; L.r[0].key<L.r[j].key; --j) //从后向前寻找插入位置
29 L.r[j+1]=L.r[j]; //记录逐个后移,直到找到插入位置
30 L.r[j+1]=L.r[0]; //将r[0]即原r[i],插入到正确位置
31 } //if
32 }
排序-插入排序-直接插入排序
1 //严2 void BInsertSort(SqList &L)3 {//对顺序表L做折半插入排序 4 for(i=2;i<=L.length;++i) 5 { 6 L.r[0]=L.r[i]; //将待插入的记录暂存到监视哨中 7 low=1;high=i-1; //置查找区间初值 8 while(low<=high) //在r[low..high]中折半查找插入的位置9 {
10 m=(low+high)/2; //折半
11 if(L.r[0].key<L.r[m].key) high=m-1; //插入点在前一子表
12 else low=m+1; //插入点在后一子表
13 } //while
14 for(j=i-1;j>=high+1; --j) L.r[j+1]=L.r[j]; //记录后移
15 L.r[high+1]=L.r[0]; //将r[0]即原r[i],插入到正确位置
16 } //for
17 }
排序-插入排序-折半插入排序
1 //希尔排序,插入排序的升级版 2 //3,8,9,5,2 len=53 //第1轮 3 5 2 8 9 gap=2 i=2 temp=9 j=0 | i=3 temp=5 j=1 | i=4 temp=2 j=2 j=0 4 //第2轮 2 3 5 8 9 gap=1 i=1 temp=5 j=0 | i=2 temp=2 j=1 j=0 j=-1 5 void shell_sort(int arr[], int len) {6 int gap, i, j;7 int temp;8 for (gap = len >> 1; gap > 0; gap = gap >> 1)9 for (i = gap; i < len; i++) {
10 temp = arr[i];
11 for (j = i - gap; j >= 0 && arr[j] > temp; j -= gap)
12 arr[j + gap] = arr[j];
13 arr[j + gap] = temp;
14 }
15 }
16 //严
17 void ShellInsert(SqList &L, int dk)
18 {//对顺序表L做一趟增量是dk的希尔插入排序
19 for(i=dk+1;i<=L.length;++i)
20 if(L.r[i].key<L.r[i-dk].key) //需将L.r[i]插入有序增量子表
21 {
22 L.r[0]=L.r[i]; //暂存在L.r[0]
23 for(j=i-dk; j>0&& L.r[0].key<L.r[j].key;j-=dk)
24 L.r[j+dk]=L.r[j]; //记录后移,直到找到插入位置
25 L.r[j+dk]=L.r[0]; //将r[0]即原r[i],插入到正确位置
26 } //if
27 }
28 void ShellSort(SqList &L,int dt[],int t)
29 {//按增量序列dt[0..t-1]对顺序表L作t趟希尔排序
30 for(k=0;k<t;++k)
31 ShellInsert(L,dt[k]); //一趟增量为dt[t]的希尔插入排序
32 }
排序-插入排序-希尔排序
1 //冒泡排序,相邻两数比较,把大的往后冒,每轮循环找最大放后面 2 //第1轮 3 8 5 2 93 //第2轮 3 5 2 8 94 //第3轮 3 2 5 8 95 //第4轮 2 3 5 8 96 void bubble_sort(int arr[],int len){7 int i,j,temp;8 for(i=0;i<len-1;i++){ // 同上 9 for(j=0;j<len-1-i;j++){ //下面有+1,所以这里减-1,防止最后一个数和外面比较越界了; 每次放一个最大的,放过的不用再比,因此-i。
10 if(arr[j]>arr[j+1]){
11 temp = arr[j];
12 arr[j]=arr[j+1];
13 arr[j+1]=temp;
14 }
15 }
16 }
17 }
18 //严
19 void BubbleSort(SqList &L)
20 {//对顺序表L做冒泡排序
21 m=L.length-1;flag=1; //flag用来标记某一趟排序是否发生交换
22 while((m>0)&&(flag==1))
23 {
24 flag=0; //flag置为0,如果本趟排序没有发生交换,则不会执行下一趟排序
25 for(j=1;j<=m;j++)
26 if(L.r[j].key>L.r[j+1].key)
27 {
28 flag=1; //flag置为1,表示本趟排序发生了交换
29 t=L.r[j]; L.r[j]=L.r[j+1]; L.r[j+1]=t;//交换前后两个记录
30 } //if
31 --m;
32 } //while
33 } //BubbleSort
排序-交换排序-冒泡排序
1 //快速排序-迭代法2 Range new_Range(int s, int e) {3 Range r;4 r.start = s;5 r.end = e;6 return r;7 }8 void swap(int *x, int *y) {9 int t = *x;10 *x = *y;11 *y = t;12 }13 //3,8,9,5,2 len=514 //第一轮:start=0 end=4 mid=9 left=0 right=4 进do left=1 left=2 {3,8,2,5,9} left=3 right=3 left=415 //第二轮:start=0 end=3 mid=8 left=0 right=3 进do left=1 {3,5,2,8,9} left=2 right=2 left=316 //第三轮:start=0 end=2 mid=5 left=0 right=2 进do left=1 {3,2,5,8,9} left=2 right=1 17 //第四轮:start=0 end=1 mid=3 left=0 right=1 进do right=0 {2,3,5,8,9} left=1 right=018 void quick_sort(int arr[], const int len) {19 if (len <= 0)20 return; // 避免len等於負值時引發段錯誤(Segment Fault)21 // r[]模擬列表,p為數量,r[p++]為push,r[--p]為pop且取得元素22 Range r[len];23 int p = 0;24 r[p++] = new_Range(0, len - 1);25 while (p) {26 Range range = r[--p];27 if (range.start >= range.end)28 continue;29 int mid = arr[(range.start + range.end) / 2]; // 選取中間點為基準點30 int left = range.start, right = range.end;31 do32 {33 while (arr[left] < mid) ++left; // 檢測基準點左側是否符合要求34 while (arr[right] > mid) --right; //檢測基準點右側是否符合要求35 36 if (left <= right)37 {38 swap(&arr[left],&arr[right]);39 left++;right--; // 移動指針以繼續40 }41 } while (left <= right);42 43 if (range.start < right) r[p++] = new_Range(range.start, right);44 if (range.end > left) r[p++] = new_Range(left, range.end);45 }46 } 47 48 //快速排序-递归法49 //3,8,9,5,2 len=550 //第一轮:start=0 end=4 mid=2 left=0 right=3 进while right=2 right=1 right=0 {2,8,9,5,3}51 //进递归,start=1 end=4 mid=3 left=1 right=3 进while right=2 right=1 {2,3,9,5,8}52 //进if递归,start=1 end=0 return53 //进递归 start=2 end=4 mid=8 left=2 right=3 进while {2,3,5,9,8} left=3 {2,3,5,8,9}54 //进if递归,start=2 end=2 return55 //进递归 start=4 end=4 return56 void quick_sort_recursive(int arr[], int start, int end) {57 if (start >= end)58 return;59 int mid = arr[end];60 int left = start, right = end - 1;61 while (left < right) {62 while (arr[left] < mid && left < right)63 left++;64 while (arr[right] >= mid && left < right)65 right--;66 swap(&arr[left], &arr[right]);67 }68 if (arr[left] >= arr[end])69 swap(&arr[left], &arr[end]);70 else71 left++;72 if (left)73 quick_sort_recursive(arr, start, left - 1);74 quick_sort_recursive(arr, left + 1, end);75 }76 void quick_sort_digui(int arr[], int len) {77 quick_sort_recursive(arr, 0, len - 1);78 }79 80 //严81 int Partition(SqList &L, int low, int high)82 {//对顺序表L中的子表r[low..high]进行一趟排序,返回枢轴位置 83 L.r[0]=L.r[low]; //用子表的第一个记录做枢轴记录 84 pivotkey=L.r[low].key; //枢轴记录关键字保存在pivotkey中 85 while(low<high) //从表的两端交替地向中间扫描 86 { 87 while(low<high&&L.r[high].key>=pivotkey) --high; 88 L.r[low]=L.r[high]; //将比枢轴记录小的记录移到低端 89 while(low<high&&L.r[low].key<=pivotkey) ++low; 90 L.r[high]=L.r[low]; //将比枢轴记录大的记录移到高端 91 } //while 92 L.r[low]=L.r[0]; //枢轴记录到位 93 return low; //返回枢轴位置 94 }95 96 void QSort(SqList &L,int low,int high) 97 {//调用前置初值:low=1; high=L.length; 98 //对顺序表L中的子序列L.r[low..high]做快速排序 99 if(low<high){ //长度大于1
100 pivotloc=Partition(L, low, high); //将L.r[low..high]一分为二,pivotloc是枢轴位置
101 QSort(L, low, pivotloc-1); //对左子表递归排序
102 QSort(L, pivotloc+1, high); //对右子表递归排序
103 }
104 }
105
106 void QuickSort(SqList &L)
107 {//对顺序表L做快速排序
108 QSort(L,1,L.length);
109 }
排序-交换排序-快速排序
1 //选择排序,用每个数字和其他依次比较,循环找第一小放第一个、在剩下的里面找第二小放第二个,…… 2 //第1轮 2 8 9 5 33 //第2轮 2 3 9 8 54 //第3轮 2 3 5 9 85 //第4轮 2 3 5 8 96 void select_sort(int arr[],int len){7 int i,j,temp; 8 for(i=0;i<len-1;i++){ //外层循环管轮数,5个数,肯定比4轮,因为最后一个数不用和自己比较,所以减一 9 for(j=i+1;j<len;j++) //每个数跟他后面的依次比较,所以加一
10 if(arr[i]>arr[j]){ //如果比后面大,就把小的放前面
11 temp = arr[i];
12 arr[i]=arr[j];
13 arr[j]=temp;
14 }
15 }
16 }
17 //严
18 void SelectSort(SqList &L)
19 {//对顺序表L做简单选择排序
20 for(i=1;i<L.length;++i){ //在L.r[i..L.length] 中选择关键字最小的记录
21 k=i;
22 for(j=i+1;j<=L.length;++j)
23 if(L.r[j].key<L.r[k].key) k=j; //k指向此趟排序中关键字最小的记录
24 if(k!=i)
25 {t=L.r[i]; L.r[i]=L.r[k]; L.r[k]=t;} //交换r[i]与r[k]
26 } //for
27 }
排序-选择排序-简单选择排序
1 //严 2 //调整堆3 void HeapAdjust(SqList &L,int s,int m)4 {//假设r[s+1..m]已经是堆,将r[s..m]调整为以r[s]为根的大根堆 5 rc=L.r[s]; 6 for(j=2*s;j<=m;j*=2) //沿key较大的孩子结点向下筛选 7 { 8 if(j<m&&L.r[j].key<L.r[j+1].key) ++j; //j为key较大的记录的下标 9 if(rc.key>=L.r[j].key) break; //rc应插入在位置s上
10 L.r[s]=L.r[j];s=j;
11 } //for
12 L.r[s]=rc; //插入
13 }
14
15 //建初堆
16 void CreatHeap(SqList &L)
17 {//把无序序列L.r[1..n]建成大根堆
18 n=L.length;
19 for(i=n/2;i>0; --i) //反复调用HeapAdjust
20 HeapAdjust(L,i,n);
21 }
22 //堆排序
23 void HeapSort(SqList &L)
24 {//对顺序表L进行堆排序
25 CreatHeap(L); //把无序序列L.r[1..L.length]建成大根堆
26 for(i=L.length;i>1;--i)
27 {
28 x=L.r[1]; //将堆顶记录和当前未经排序子序列L.r[1..i]中最后一个记录互换
29 L.r[1]=L.r[i];
30 L.r[i]=x;
31 HeapAdjust(L,1,i-1); //将L.r[1..i-1]重新调整为大根堆
32 } //for
33 }
排序-选择排序-堆排序
选择排序还有树形选择排序,就是比赛用的那种。
1 //严2 //相邻两个有序子序列的归并3 void Merge(RedType R[],RedType T[],int low,int mid,int high)4 {//将有序表R[low..mid]和R[mid+1..high]归并为有序表T[low..high]5 i=low;j=mid+1;k=low;6 while(i<=mid&&j<=high) //将R中记录由小到大地并入T中7 {8 if(R[i].key<=R[j].key) T[k++]=R[i++];9 else T[k++]=R[j++];10 } //while11 while(i<=mid) T[k++]=R[i++]; //将剩余的R[i..mid]复制到T中12 while(j<=high) T[k++]=R[j++]; //将剩余的R[j.high]复制到T中13 }14 //归并排序15 void MSort(RedType R[],RedType &T[],int low,int high)16 {//R[low..high]归并排序后放入T[low..high]中 17 if(low==high) T[low]=R[low]; 18 else 19 { 20 mid=(low+high)/2; //将当前序列一分为二,求出分裂点mid 21 MSort(R,S,low,mid); //对子序列R[low..mid]递归归并排序,结果放入S[low..mid] 22 MSort(R,S,mid+1,high); //对子序列R[mid+1..high]递归归并排序,结果放入S[mid+1..high] 23 Merge(S,T,low,mid,high);//将S[low..mid]和S[mid+1..high]归并到T[low..high] 24 } //else 25 } 26 void MergeSort(SqList &L) 27 {//对顺序表L做归并排序 28 MSort(L.r,L.r,1,L.length); 29 } 30 31 //归并排序-之迭代法 32 //大致想法是,相邻两数比,变成小大、小大、小大,然后变宽,再比,变成小小大大、…… ;再变宽,小小小小大大大大、……,33 //以此类推,每一轮只要两两比较 小小小小,大大大大的值,把新结果放到新数组里,剩下的抄到后面即可34 //这个有种2分法逆着用的感觉,因为变宽(seg)总以2的指数级增长,所以这个算法快不快,取决于边界值能不能快点比完,比如小小小小都小于大,那么后面3个大直接抄就行35 int min(int x, int y) {36 return x < y ? x : y;37 }38 //3,8,9,5,2 len=539 //第一轮 seg=1 start=0 low=0 mid=1 high=2 k=0 start1=0 end1=1 start2=1 end2=2 b[0]=3,k=1,start1=1 b[1]=8 k=2 start2=2 40 // start=2 low=2 mid=3 high=4 k=2 start1=2 end1=3 start2=3 end2=4 b[2]=5 k=3,start2=4 b[3]=9 k=4 start1=341 // start=4 low=4 mid=5 high=5 k=4 start1=4 end1=5 start2=5 end2=5 b[4]=2 k=5,start1=542 // start=6 exit43 // a[]={3,8,5,9,2}44 //第二轮 seg=2 start=0,low=0 mid=2 high=4 k=0 start1=0 end1=2 start2=2 end2=4 b[0]=3 k=1 start1=1 b[1]=5 k=2 start2=3 b[2]=8 k=3 start1=2 b[3]=9 k=4 start2=445 // start=4,low=4,mid=5 high=5 k=4 start1=4 end1=5 start2=5 end2=5 b[4]=2 k=5,start1=546 // a[]={3,5,8,9,2}47 //第三轮 seg=4 start=0 low=0 mid=4 high=5 k=0 start1=0 end1=4 start2=4 end2=5 b[0]=2 k=1 start2=5 b[1]=3 k=2 start1=1 b[2]=5 k=3 start1=2 b[3]=8 k=4 start1=3 b[4]=9 k=5 start1=4 48 // start=8 exit49 // a[]={2,3,5,8,9}50 //第三轮 seg=8 exit51 void merge_sort(int arr[], int len) {52 int* a = arr; //指向要排序的数组 53 int* b = (int*) malloc(len * sizeof(int));//临时存放每轮排序结果 54 int seg, start;55 for (seg = 1; seg < len; seg += seg) {56 for (start = 0; start < len; start += seg + seg) {57 //按照分段大小,先确定段与段之间的界限 58 int low = start, mid = min(start + seg, len), high = min(start + seg + seg, len);59 int k = low;60 int start1 = low, end1 = mid;61 int start2 = mid, end2 = high;62 //段内元素两两比较,小的放到临时数组 63 while (start1 < end1 && start2 < end2)64 b[k++] = a[start1] < a[start2] ? a[start1++] : a[start2++];65 //其中一段全比完了,剩下一段直接抄到后面 66 while (start1 < end1)67 b[k++] = a[start1++];68 //其中一段全比完了,剩下一段直接抄到后面 69 while (start2 < end2)70 b[k++] = a[start2++];71 }72 //把这种分段下排好的临时数组,作为下次要排序的数组 73 int* temp = a;74 a = b;75 b = temp;76 }77 //释放b空间,我也不知道为啥要重新赋值再释放 78 if (a != arr) {79 int i;80 for (i = 0; i < len; i++)81 b[i] = a[i];82 b = a;83 }84 free(b);85 }86 87 //归并排序-之递归法 88 //3,8,9,5,2 len=589 //start=0,end=4,len=4,mid=2,start1=0,end1=2 start2=3 end2=4 入栈 90 //start=0,end=2 len=2 mid=1 start1=0,end1=1 start2=2 end2=2 入栈91 //start=0,end=1 len=1 mid=0 start1=0 end1=0 start2=1 end2=1 入栈92 //start=0 end=0 return end1=0出栈 start2=1入栈直接出栈,代码第一次往下执行93 //代码第一次往下执行 k=0 reg[0]=3,start1=1,k=1 reg[1]=8 start2=2 arr[0]=3 arr[1]=894 //上步代码走完,return end1=1出栈 start2=2入栈直接出栈,代码第二次往下执行95 //代码第二次往下执行 k=0 reg[0]=3 start1=1 k=1 reg[1]=8 start1=2 k=2 reg[2]=9 start2=3 k=3 arr[0]=3 arr[1]=8 arr[2]=996 //上步代码走完,return end1=2出栈 start2=3入栈,97 //start=3,end=4 len 1 mid=3 start1=3 end1=3 start2=4 end2=4 入栈直接出栈,入栈直接出栈,代码第三次往下执行98 //代码第三次往下执行 k=3 reg[3]=2 start2=5 k=4 reg[4]=5 k=5 start1=4 arr[3]=2 arr[4]=599 //arr[]={3,8,9,2,5}
100 //上步代码走完,第一行 start=0,end=4完成了两个递归,继续往下,
101 //代码第四次往下走 k=0,reg[0]=2,start1=1,k=1, reg[1]=3,start1=2,k=2 reg[2]=5 start2=4 k=3 reg[3]=8 start2=4 k=4 reg[4]=9
102 //arr[]={2,3,5,8,9}
103
104 void merge_sort_recursive(int arr[], int reg[], int start, int end) {
105 if (start >= end)
106 return;
107 int len = end - start, mid = (len >> 1) + start;
108 int start1 = start, end1 = mid;
109 int start2 = mid + 1, end2 = end;
110 merge_sort_recursive(arr, reg, start1, end1);
111 merge_sort_recursive(arr, reg, start2, end2);
112 int k = start;
113 while (start1 <= end1 && start2 <= end2)
114 reg[k++] = arr[start1] < arr[start2] ? arr[start1++] : arr[start2++];
115 while (start1 <= end1)
116 reg[k++] = arr[start1++];
117 while (start2 <= end2)
118 reg[k++] = arr[start2++];
119 for (k = start; k <= end; k++)
120 arr[k] = reg[k];
121 }
122 void merge_sort_digui(int arr[], const int len) {
123 int reg[len];
124 merge_sort_recursive(arr, reg, 0, len - 1);
125 }
排序-归并排序
1 //严2 //链式基数排序3 //定义 4 #define MAXNUM_KEY 8 //关键字项数的最大值5 #define RADIX 10 //关键字基数,此时是十进制整数的基数6 #define MAX_SPACE 100007 typedef struct8 {9 KeyType keys[MAXNUM_KEY]; //关键字
10 InfoType otheritems; //其他数据项
11 int next;
12 }SLCell; //静态链表的结点类型
13 typedef struct
14 {
15 SLCell r[MAX_SPACE]; //静态链表的可利用空间,r[0]为头结点
16 int keynum; //记录的当前关键字个数
17 int recnum; //静态链表的当前长度
18 }SLList; //静态链表类型
19 typedef int ArrType[RADIX] //数组类型
20
21 //排序
22 void Distribute(SLCell &r,int i,ArrType &f,ArrType &e)
23 {//静态链表L的r域中记录已按(keys[0], …, keys[i-1])有序
24 //本算法按第i个关键字keys[i]建立RADIX个子表,使同一子表中记录的 keys[i]相同
25 //f[0..RADIX-1]和e[0..RADIX-1]分别指向各子表中第一个和最后一个记录
26 for(j=0;j<RADIX;++j) f[j]=0; //各子表初始化为空表
27 for(p=r[0].next;p;p=r[p].next)
28 {
29 j=ord(r[p].keys[i]); //ord将记录中第i个关键字映射到[0..RADIX-1]
30 if(!f[j]) f[j]=p;
31 else r[e[j]].next=p;
32 e[j]=p; //将p所指的结点插入第j个子表中
33 } //for
34 }
35
36 void Collect(SLCell &r,int i,ArrType f,ArrType e)
37 {//本算法按keys[i]自小至大地将f[0..RADIX-1]所指各子表依次链接成一个链表
38 //e[0..RADIX-1]为各子表的尾指针
39 for(j=0;!f[j]; j=succ(j)); //找第一个非空子表,succ为求后继函数
40 r[0].next=f[j]; t=e[j]; //r[0].next指向第一个非空子表中第一个结点
41 while(j<RADIX)
42 {
43 for(j=succ(j);j<RADIX-1&&!f[j];j=succ(j)); //找下一个非空子表
44 if(f[j]) {r[t].next=f[j]; t=e[j];} //链接两个非空子表
45 } //while
46 r[t].next=0; //t指向最后一个非空子表中的最后一个结点
47 }
48
49 void RadixSort(SLList &L)
50 {//L是采用静态链表表示的顺序表
51 //对L做基数排序,使得L成为按关键字自小到大的有序静态链表,L.r[0]为头结点
52 for(i=0;i<L.recnum;++i) L.r[i].next=i+1;
53 L.r[L.recnum].next=0; //将L改造为静态链表
54 for(i=0;i<L.keynum;++i) { //按最低位优先依次对各关键字进行分配和收集
55 Distribute(L.r,i,f,e); //第i趟分配
56 Collect(L.r,i,f,e); //第i趟收集
57 } //for
58 }
排序-基数排序-定义、排序
《数据结构》严蔚敏与陈越伪代码总结相关推荐
- 构建线性表的c语言代码,数据结构严蔚敏C语言版—线性表顺序存储结构(顺序表)C语言实现相关代码...
1.运行环境 这里说明一下这里所有的C语言代码都是基于code::blocks 20.03编译运行的.当然一些其他集成开发环境应该也是可以的,个人不太喜欢功能太过强大的IDE,因为那同样意味着相关设置 ...
- 数据结构与算法(陈越版)第五讲 (树下)树的应用——集合及其运算
数据结构与算法(陈越版)第五讲 (树下)树的应用--集合及其运算 一.集合的表示 1.1.集合的表示 1.2.集合的储存 二.集合的运算 2.1查找以及普通并 2.2按照秩的合并算法 2.3路径压缩优 ...
- 数据结构 严蔚敏 第二章 线性表
数据结构 严蔚敏 第二章 线性表 线性表:由n个(n>=0)数据特征相同的元素构成的有限序列. 线性表的类型定义表示和实现 顺序表 存储单元地址连续 随机存取 若每个元素占用 m 个存储单元,以 ...
- 【计算机】数据结构-严蔚敏/清华大学P3
[计算机]数据结构-严蔚敏/清华大学P1 第二章 线 性表 线性结构 是 一个数据元素的有序(次序)集 线性结构的基本特征: 1. 集合中必存在唯一的一个"第一元素": ...
- 数据结构严蔚敏C语言版—线性表顺序存储结构(顺序表)C语言实现相关代码
数据结构严蔚敏C语言版-线性表顺序存储结构(顺序表)C语言实现相关代码 1.运行环境 2.准备工作 1)项目构建 1>新建一个SeqList项目 2>新建两个文件Sources和Heade ...
- 数据结构----严蔚敏
最近一直想找一本纯数据结构的书来学习,找来找去都没有找到一本合适的书籍,相比之下国内的书籍之中,严蔚敏和吴伟民的还算是经典版了,很多国内其他数据结构教材都参考这本书的.但缺点是很多都是伪代码,对编程初 ...
- 数据结构与算法(陈越)(学习笔记)(更新ing)
数据结构(陈越) 一.数据结构(计算运行时间) #include<stdio.h> #include<time.h> #include<math.h> clock_ ...
- 数据结构严蔚敏清华大学pdf_2019年清华大学自动化系控制工程专业大数据方向考研经验分享...
基本情况(以下内容仅代表个人观点) 我目前就读于西南某双非石油工程专业,2019考研报考清华大学自动化系大数据工程专业,一志愿复试被刷,侥幸调剂录取至微电子系.初试总分346分(政治-63 + 英语一 ...
- 数据结构 绪论+视频资料(修订版)严蔚敏、陈文博版
资料(我感觉老师讲的不错,通俗易懂 需要自取,比较有逻辑 老师是赵海英) 链接: https://pan.baidu.com/s/1zJ-6nvT_0Ya21liHuQS-sw 密码: 496e ht ...
最新文章
- [优先队列] 洛谷 P2085 最小函数值
- Ubuntu11.10下载android4.0.1源码
- gulp几个常见问题及解决方案
- HTML5开发 桌面提醒功能
- postgresql 动态添加过滤条件_通过窗口函数进行过滤导致Postgresql
- python面试设计模式问题_聊聊 Python 面试最常被问到的几种设计模式(下)
- eclipse linux远程调试工具,使用本地Eclipse IDE调试器与远程项目源(Linux)
- bind mysql django_Django+bind dlz DNS管理平台
- 云服务器 ECS > 网络 > 经典网络迁移至专有网络
- docker入门与部署微服务--学习笔记
- spring 官方文档
- ubuntu 编译android .img_全网可用交叉编译工具链大全
- 数据结构和算法——线性结构(1)数组、栈、队列和单链表
- 产品必备技能(五):如何使用商业画布分析一款产品?附实操报告
- 我的gitbub的学习目录
- 雷达的工作原理示意图_雷达测距原理.ppt
- 为什么要“推销自己”?
- 小白入门指南|zookeeper快速入门
- vue获取当前时间、时间戳方法
- 免费图片素材网站收集