《数据结构》严蔚敏与陈越伪代码总结
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 }
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 }
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 }
1 //严 2 //用邻接表表示 3 void DFS_AL(ALGraph G,int v){ //图G为邻接矩阵类型,从第v个顶点出发,深度优先搜索遍历图G 4 cout<<v; //访问第v个顶点 5 visited[v]=true; //并把它的标志数组值置为true 6 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 }
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 }
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 }
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 }
1 //最短路径问题 2 //单源-无权-BFS 3 //单源-有权-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 }
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 }
1 //有向无环图 Directed Acyclic Graph简称DAG,有方向的,没有首尾相连的图 2 //AOV网,顶点活动网(Activity On Vertex network),顶点表示活动、边表示活动间先后关系的有向图 3 //AOV是DAG, 首尾相连就没有起点了,也没有顺序,且会死循环 4 //AOV中所有活动组成线性序列,叫做拓扑序列Topological order, 5 //由AOV构造 拓扑序列的过程叫做拓扑排序Topological sort 6 //两种算法可实现拓扑排序 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 }
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 }
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树的查找结果类型
1 //严 2 Result SearchBTree(BTree T,KeyType key){ 3 //在m阶B树上查找关键字key,返回Result类型结果 4 //若查找成功,则特征值tag=1,指针pt所指结点中,第i个关键字等于key 5 //否则特征值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 }
1 //严 2 Status InsertBTree(BTree &T,KeyType K,BTree q,int i){ 3 //在m阶B树T上结点*q的key[i]与key[i+1]之间插入关键字K 4 //若引起结点过大,则沿双亲链进行必要的分裂调整,使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 }
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 2 9 //第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=5 3 //第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 9 3 //第2轮 3 5 2 8 9 4 //第3轮 3 2 5 8 9 5 //第4轮 2 3 5 8 9 6 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=5 14 //第一轮: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=4 15 //第二轮:start=0 end=3 mid=8 left=0 right=3 进do left=1 {3,5,2,8,9} left=2 right=2 left=3 16 //第三轮: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=0 18 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 do 32 { 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=5 50 //第一轮: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 return 53 //进递归 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 return 55 //进递归 start=4 end=4 return 56 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 else 71 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 3 3 //第2轮 2 3 9 8 5 4 //第3轮 2 3 5 9 8 5 //第4轮 2 3 5 8 9 6 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 } //while 11 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=5 39 //第一轮 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=3 41 // start=4 low=4 mid=5 high=5 k=4 start1=4 end1=5 start2=5 end2=5 b[4]=2 k=5,start1=5 42 // start=6 exit 43 // 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=4 45 // start=4,low=4,mid=5 high=5 k=4 start1=4 end1=5 start2=5 end2=5 b[4]=2 k=5,start1=5 46 // 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 exit 49 // a[]={2,3,5,8,9} 50 //第三轮 seg=8 exit 51 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=5 89 //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]=8 94 //上步代码走完,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]=9 96 //上步代码走完,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]=5 99 //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 10000 7 typedef struct 8 { 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 }