码迷,mamicode.com
首页 > 编程语言 > 详细

数据结构与算法分析(5)表、栈和队列(一)

时间:2016-05-27 18:20:17      阅读:254      评论:0      收藏:0      [点我收藏+]

标签:

      本节讨论最简单和最基本的三种数据结构:表,栈和队列。

    每种程序都明晰地至少使用一种这样的数据结构,而栈在程序中总要间接地用到。

      内容:

      1.介绍抽象数据类型(ADT)的概念;

      2.阐述如何对表进行有效的操作;

      3.介绍栈ADT及其在实现递归方面的应用;

      4.介绍队列ADT及其在操作系统和算法设计上的与应用。

 

    (1)抽象数据类型

      程序设计的基本法则之一是:例程不应超过一页。

      模块化的优点:

      1)调试小程序比调试大程序容易的多;

      2)多个人同时对一个模块式程序编程更加容易;

      3)一个写得好的模块化程序把某些依赖关系只局限在一个例程中,这样使得修改起来更加容易。

      由模块化是有益的可以推出:全局变量和副作用是有害的。

      抽象数据类型(abstract data type ADT)是一些操作的集合。对诸如表、集合、图和他们的操作一起可看作是抽象数据类型。对于集合ADT,我们有诸如并,交,测定大小以及取余等操作。或者我们也可以只要两种操作:并和查找,这两种操作又在集合上定义了一种不同的ADT

 

    (2)表ADT

      几个概念:

      1)空表:大小为0的表;

      2)后继元:当前元素的后一个;

      3)前驱元:当前元素的前一个;

      与ADT的定义有关的就是在ADT上进行操作的集合了:printList,makeEmpty,find,findKth,findPreviousinsert,delete等。

      2.1表的简单数组实现:

    对表的所有操作都可以使用数组来实现。虽然数组是动态指定的,但是还是需要对表的大小的最大值进行估算。这会导致有可能浪费大量的空间。数组实现使得PrintListFind以线性时间执行,FindKth以常数时间。而插入和删除的代价昂贵。

      因为插入和删除的运行时间是如此的慢以及表的大小必须事先已知,所以简单数组一般不用来实现表这种结构。

      2.2链表

      为了避免插入和删除的线性开销,我们允许表可以不连续存储。

      链表由一系列在不必再内存中相连的结构组成。每一个结构均包含表元素和包含指向该元素后继元的Next指针。最后一个单元的Next指针指向NULLANSI C规定NULL0

  图:

      一个链表:

    技术分享

     从链表中删除一个元素:

     技术分享

      向链表中插入:

    技术分享  

      2.3程序设计细节:

      可能遇到的问题:

      1)不存在从所给定义出发在表的前面插入元素的真正显示的方法;

      2)从表的前面实行删除是一个特殊情况,因为它改变了表的起始段,在编程中对疏忽可能导致表的丢失。

      3)在一般的删除中要求我们记住被删除单元前面的表元。

      为了解决这个问题,我们通常留出一个标记结点,有时我们称之为表头(header)或者哑结点(dummy node)。同时为了避免删除中的一些问题,我们需要编写例程findPrevious返回我们要删除表元的前驱元的位置。表头的使用能够使我们表达基本的指针操作而又不致使特殊情形的代码含糊不清。

      在处理链表的删除操作的相关问题时,我们需要编写例程findPrevious(),它将返回我们要删除的表元的前驱元的位置。如果我们使用头节点,那么当我们删除表的第一个元素时,findPrevious()将返回表头的位置。

      2.4单向链表:

      单向链表的ADT的例程:

#ifndef_List_H

struct Node;
typedef struct Node *PtrToNode;
typedef PtrToNode List;//另起一个名字
typedef PtrToNode Position;
typedef int ElementType;

List MakeEmpty(List L);
int IsEmtpy(List L);
int IsLast(Position P,List L);
Position Find(ElementType X,List L); 
void Delete(ElementType X,List L);
Position FindPrevious(ElementType X,List L);
void Insert(ElementType X,List L,Position P);
void DeleteList(List L);
Position Header(List L);
Position First(List L);
ElementType Retrieve(Position P);

#endif  /* _List_H */

/*Node结点的声明是在.c文件中(Place in the implementation file)*/
struct Node{
  ElementType Element;
  Position Next; 
};
//测试一个链表是否为空表 
int IsEmtpy(List L){
    return L->Next==NULL;
}
//测试当前位置是不是链表的尾部 
int IsLast(Position    P,List L){
  return P->next==NULL;    
}
//Find例程
Position Find(ElementType X,List L){
    Position P;    
    P=P->Next;
    while(P!=NULL&&P->Element!=X){
        P=P->Next;
    }
    return P;
} 
//链表的删除例程
void Delete(ElementType    X,List L){
    Position P,TmpCell;
    P=FindPrevious(X,L);
    if(!IsLast(P,L)){ //这里需要判断是否是链表的最后一个结点,如果是,则表示找的元素未在链表中 
        TmpCell=P->Next;
        P->Next=TmpCell->Next;
        free(TmpCell); 
    }
} 
//找到元素结点的前一个结点,找不到就返回链表的最后的结点 
Position FindPrevious(ElementType X,List L){
    Position P;
    P=L;
    while(P->Next!=NULL&&P->Next->Element!=X){
        P=P->Next;
    }
    return P;
}
//链表的插入例程
void Insert(ElementType    X,List L,Position P){
    Position TmpCell;
    TmpCell=malloc(sizeof(struct Node));
    if(TmpCell==NULL){
      printf("Error!\n");    
    }else{
      TmpCell->Element=X;
      TmpCell->Next=P->Next;
      P->Next=TmpCell;    
    }
} 
void DeleteList(List L){
  Position P,Tmp;
  P=L->Next;
  L->Next=NULL;
  while(P!=NULL){
      Tmp=p;
      P=P->Next;
      free(Tmp);
  }    
} 

      在表的例程运用中的几个提醒:

      1.指针变量包含伪地址,系统提醒"memory access vialation"或"segmentation violation"。例如:{free(p);p=p->Next;}

      2.声明一个指向结构的指针并不创建该结构,而只是给出足够的空间容纳结构可能使用的地址。创建尚未声明过的记录的一般方法是使用malloc库函数。malloc创建一个新的结构并返回指向该结构体的指针。一些比较老的编译器需要在malloc的前面加上类型转换(type cast)。C语言提供了两种动态分配内存空间的库函数,malloc和calloc。他们都要求包含stdlib头文件。

      3.free(p)的作用是:p正在指向的地址没变,但在该地址处的数据此时已经无定义了。

      4.malloc(sizeof(PtrToNode))是合法的,但是它并不给结构体分配足够的内存空间,他只给指针分配内存空间。

      单向链表的实例:

      1)生成100个随机整数并放入一个链表中,要求链表中的元素按从小到大顺序排列:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

struct Node{
    int Element;
    struct Node *Next;
};
typedef struct Node *List;
typedef struct Node *PtrToNode; 

List create(){
  List L;
  PtrToNode header=malloc(sizeof(struct Node));
  header->Next=NULL; 
  L=header;
  return L;
}

//递归的有序的插入 
void InsertRecursive(PtrToNode    temp,List L){
    PtrToNode p=L;
    if(p->Next==NULL){
        temp->Next=p->Next;
        p->Next=temp;
    }
    else if(p->Next!=NULL){
        if(temp->Element<=p->Next->Element){
            temp->Next=p->Next;  //temp指向p的指向的下一个元素 
            p->Next=temp;        //p指向temp 
        }else if(temp->Element>p->Next->Element){
            InsertRecursive(temp,p->Next);
        }
    }
}

//非递归有序的插入 
void InsertUnRecursive(PtrToNode temp,List L){
    PtrToNode p=L;
    //一个元素也没插入时 
    if(p->Next==NULL){
        temp->Next=p->Next;
        p->Next=temp;
        return;
    }
    //只有一个元素时 
    if((p->Next!=NULL)&&(p->Next->Next==NULL)){
        if((temp->Element)<=(p->Next->Element)){
            temp->Next=p->Next;
            p->Next=temp;
        }else if(temp->Element>p->Next->Element){
            temp->Next=p->Next->Next;
            p->Next->Next=temp;
        }
        return;
    }
    while(p->Next!=NULL&&p->Next->Next!=NULL){
        if(temp->Element<=p->Next->Element){
            temp->Next=p->Next;
            p->Next=temp;
            return;
        }else if(temp->Element>p->Next->Element&&temp->Element<=p->Next->Next->Element){
            temp->Next=p->Next->Next;
            p->Next->Next=temp;
            return;
        }else{
            p=p->Next;
        }
        //有两个元素,但执行p=p->Next时有可能碰到p->Next->Next==NULL; 
        if(p->Next->Next==NULL){
          if((temp->Element)<=(p->Next->Element)){
            temp->Next=p->Next;
            p->Next=temp;
          }else if(temp->Element>p->Next->Element){
            temp->Next=p->Next->Next;
            p->Next->Next=temp;
          }
          return;
        }
    } 
} 

void printAll(List list){
  PtrToNode p=list;
  int flag=1;
  while(p->Next!=NULL){
      printf("a[%2d]=%3d ",flag,p->Next->Element);
      p=p->Next;
      if(flag%10==0){
      printf("\n");     
    }
       flag++;
  }    
}

int main(){
  srand(time(NULL));
  List list=create();
  int i,x;
  PtrToNode p;
  //InsertRecursive与InsertUnRecursive函数具有一样的功能: 
  for(i=0;i<50;i++){
      x=rand()%1000;
      p=malloc(sizeof(struct Node));
      p->Element=x;
      InsertRecursive(p,list);
  }
  for(i=0;i<50;i++){
      x=rand()%1000;
      p=malloc(sizeof(struct Node));
      p->Element=x;
      InsertUnRecursive(p,list);
  }
  //输出插入的结果
  printAll(list); 
} 

技术分享

      2)将两个从小到大排列的链表合并为一个新链表,要求:

    (1)原来的两个链表不保存(合并时,无需生成新的空间来存放每个结点,直接将所有结点合并为新链表)

    (2)原来的两个链表不作改变(合并时,对每一个结点需要复制并产生新链表)

    (3)对以上两小题,若链表中遇到有相同的元素,则在合并时去掉重复元素。(当然,你也可以在链表合并完以后再扫描整个链表去掉重复元素,但这需要额外的运行时间,因此并不是一个好的办法)

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

struct Node{
    int Element;
    int flag;    //用来不重复插入相同数据,做个标记 
    struct Node *Next;
};

typedef struct Node *List;
typedef struct Node *PtrToNode; 
typedef PtrToNode Position;

//创建具有头节点的链表 
List create(){
  List L;
  PtrToNode header=malloc(sizeof(struct Node));
  header->Next=NULL; 
  L=header;
  return L;
}
//执行插入操作,参数表示,element将插入到posi所指向的元素的后面 
void Insert(int element,List list,Position posi){
    PtrToNode p=list;//用作循环遍历链表,找到地址与posi相同的结点 
    PtrToNode temp;//用来新建结点 
    while(p!=posi){
        p=p->Next;
    }//找到posi所在位置 
    if(p==list){//a1.当位置在头节点 
      if(p->Next==NULL){//a1.b1在头节点,当头结点的下一个为空时,直接插入 
        temp=malloc(sizeof(struct Node));
        temp->Element=element;
        temp->flag=1;
        temp->Next=p->Next;
        p->Next=temp;    
      }else{//a1.b2在头节点,当头结点的下一个不为空时 
          if(element==p->Next->Element){//a1.b2.c1当要插入的元素与位置指向的下一个元素相同时,不用重复插入 
              p->Next->flag++;
          }else{//a1.b2.c2不同时,肯定小于,所以插入 
             temp=malloc(sizeof(struct Node));
            temp->Element=element;
            temp->flag=1;
            temp->Next=p->Next;
            p->Next=temp;    
          }
      }
    //a2.当位置不在头节点 
    }else if(p!=list){
      if(element==posi->Element){//a2.b1当要插入元素与当前位置元素相同时,不插入 
           posi->flag++;
           return;
      }else{//a2.b2当不同时,肯定大于当前元素 
        temp=malloc(sizeof(struct Node));
        temp->Element=element;
        temp->flag=1;
        temp->Next=p->Next;
        p->Next=temp;
      }
    }
}

//一下这部分的功能是找到要插入的位置 
Position FindInsertPosition(List list,int element){
    PtrToNode p=list;
    Position position;
    while(p!=NULL){
        if(p->Next==NULL){//a1如果下一个元素为空,则一定是这个位置 
            position=p;
            break;
          }else if(p->Next!=NULL){//a2如果下一个不为空 
               if(element<=p->Next->Element){//a2.b1要插入元素小于或等于下一个元素,都可以插在p和p指向的下一个元素之间 
              position=p;
              break;
            }else if(element>p->Next->Element){//a2.b2当要插入元素还大于p指向的下一个元素时,肯定插入点在下一个元素的后面,只需循环遍历 
                 p=p->Next;
             }
        }      
   }
   return position;
} 

void InsertWithNode(PtrToNode temp,List list,Position posi){
       PtrToNode p=list;//用作循环遍历链表,找到地址与posi相同的结点 
       int element=temp->Element;
    while(p!=posi){
        p=p->Next;
    }//找到posi所在位置 
    if(p==list){//a1.当位置在头节点 
      if(p->Next==NULL){//a1.b1在头节点,当头结点的下一个为空时,直接插入 
        temp->Next=p->Next;
        p->Next=temp;    
      }else{//a1.b2在头节点,当头结点的下一个不为空时 
          if(element==p->Next->Element){//a1.b2.c1当要插入的元素与位置指向的下一个元素相同时,不用重复插入 
              p->Next->flag+=temp->flag;
              free(temp);
          }else{//a1.b2.c2不同时,肯定小于,所以插入 
            temp->Next=p->Next;
            p->Next=temp;    
          }
      }
    //a2.当位置不在头节点 
    }else if(p!=list){
      if(element==posi->Element){//a2.b1当要插入元素与当前位置元素相同时,不插入 
           posi->flag+=temp->flag;
           free(temp);
           return;
      }else{//a2.b2当不同时,肯定大于当前元素 
        temp->Next=p->Next;
        p->Next=temp;
      }
    }
}
List UnitTwoList(List list1,List list2){
    //让将要返回的链表先指向第一个,然后将第二个链表的每个元素依次插入 
    List list=list1;
    PtrToNode ptr=list2->Next;
    Position position; 
    PtrToNode ptrD=ptr;
    while(ptr!=NULL){
      //对于链表2中的每个元素都要依次找出其在链表1中需要插入的位置 
      position=FindInsertPosition(list,ptr->Element);
      //Insert(ptr->Element,list,position);
      //ptr=ptr->Next;
      ptrD=ptr->Next; 
      InsertWithNode(ptr,list,position);
      ptr=ptrD;
    }
    return list;    
}

void printListWithFlag(List list){
    PtrToNode p=list->Next;
    int i,t=1;
    while(p!=NULL){
        for(i=1;i<=p->flag;i++){
            printf("L[%2d]=%3d ",t,p->Element);
            if(t%10==0){
             printf("\n");
            }
               t++;
        }
        p=p->Next;
    }
}

void initList(List list){
    int x,i;
    Position position;
    for(i=0;i<50;i++){
      x=rand()%1000;
      printf("%4d",x);
      if((i+1)%25==0){
        printf("\n");
      }
      position=FindInsertPosition(list,x);
        Insert(x,list,position);
    }
}
int main(){
    srand(time(NULL));
    List list_a=create();
    List list_b=create();
    //初始化第一个链表 
    initList(list_a);
    //初始化第二个链表 
    initList(list_b);
    printf("\n"); 
    printf("输出list_a:\n");
    printListWithFlag(list_a);
    printf("输出list_b:\n");
    printListWithFlag(list_b);
    List list=UnitTwoList(list_a,list_b);
    printf("输出合并后的list:\n");
    printListWithFlag(list);
    return 0;
}

技术分享

       

      2.5双向链表:

      双向链表用来倒序扫描链表很方便,而且简化了删除操作,不再迫使使用一个指向前驱元的指针来访问一个关键字。

      实例:编写程序,从键盘输入10个整数并放入一个循环双向链表中(不排序),然后按输入顺序输出这些整数和逆序输出这些整数。

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

struct Node{
  struct Node *Pre;
  int Element;
  struct Node *Next;
};
typedef struct Node *List;
typedef struct Node *PtrToNode;

List create(){
    List list;
    PtrToNode header,tailer;
    header=malloc(sizeof(struct Node));
    tailer=malloc(sizeof(struct Node));
    list=header;
    header->Pre=tailer;
    header->Next=tailer;
    tailer->Pre=header;
    tailer->Next=header;
    return list;
}
void Insert(List list,int x){
    PtrToNode temp;
    PtrToNode p=list;
    temp=malloc(sizeof(struct Node));
    temp->Element=x;
  
    while(p->Next!=list){
         p=p->Next;//找到尾节点
    }
      temp->Next=p;
      temp->Pre=p->Pre; 
      p->Pre->Next=temp;
      p->Pre=temp;
      
}
 void PrintTwoDListOrder(List list){
     printf("依次顺序输出的结果为:\n"); 
     PtrToNode p=list;
     int i=1;
     while(p->Next!=list){
         if(p->Next!=list->Pre){
           printf("第%d个元素为%2d  ",i,p->Next->Element);                    
            p=p->Next;
            if(i%5==0){
                 printf("\n");
               }
               i++;    
               continue;
         } 
         break;
     }
 }
void PrintTwoDListNOrder(List list){
    printf("依次逆序输出的结果为:\n"); 
    PtrToNode p=list->Pre;
     int i=1;
     while(p->Pre!=list->Pre){
         if(p->Pre!=list){
           printf("第%d个元素为%2d  ",i,p->Pre->Element);                    
            p=p->Pre;
            if(i%5==0){
                  printf("\n");
               }
               i++;     
               continue;
         } 
         break;
     }
}
int main(){
    //创建一个有头有尾的双向链表
    srand(time(NULL));
    List list=create();
    int i,x;
    for(i=0;i<10;i++){
      x=rand()%100; 
      printf("生成的随机数为%2d  ",x);
      if((i+1)%5==0){
          printf("\n");
      }
      Insert(list,x);
    } 
    PrintTwoDListOrder(list);
    PrintTwoDListNOrder(list);
    return 0;
} 

技术分享

      双向链表的另一个特例是循环链表,即让最后的单元反过来指向第一个单元。循环链表也可以不是双向链表。这种结构在某些应用程序中很流行。

 

    2.6十字链表

    主链表上的每个结点都是支链表的头结点:

    实例:随机抽取20张扑克牌(扑克牌有两项数据,一为花色,二为大小),花色按黑桃、红桃、梅花、方块次序排列,要求建立链表来存放这些扑克牌,最后输出。

    (1)先按花色,再按大小排列

技术分享

      (2)先按大小,再按花色排列

技术分享

      注:一副牌共有52张,每张不能重复,请考虑如何随机产生不重复的牌。

      先按花色排序,后按大小:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

struct Poker{
  int Element;
  int Color;
  int Num; 
  struct Poker *mainNext;
  struct Poker *BranchNext;    
}; 
typedef struct Poker *List;
typedef struct Poker *PtrToNode;

void InitNode(PtrToNode p){
  if(p->Element%13==0){
      p->Num=13;
      p->Color=p->Element/13-1;
  }else{
      p->Num=p->Element%13;
      p->Color=p->Element/13;
  }
}  
//用数组辅助产生不重复的52以内的无序的整数20个包含52  
void InitDisOrder(int a[]){
  int s[52];
  int i,x;
  for(i=0;i<52;i++){
    s[i]=1;
  }
  for(i=0;i<20;i++){
L:  x=rand()%52;//产生1到52的随机数
    if(s[x]==0){
      goto L;
    }else{
      a[i]=x+1;
      s[x]=0;
    }    
  }
}
//用数组辅助产生不重复的有序的整数20个包括52 
void InitOrder(int a[]){
    int s[52];
    int i,j,x;
    for(i=0;i<52;i++){
      s[i]=1;    
    }
    for(i=0;i<20;i++){
L:        x=rand()%52;
        if(s[x]==0){
            goto L;
        }else
        s[x]=0;
    }
    for(i=0;i<52;i++){
      if(s[i]==0){
        a[j]=i+1;
        j++;        
      }else
      continue;
    }
}
PtrToNode InsertBranch(List list,int x){
  PtrToNode p1,p2,temp;
  p1=p2=list;
  temp=malloc(sizeof(struct Poker));
  temp->Element=x;
  temp->mainNext=NULL;
  temp->BranchNext=NULL;
  InitNode(temp);
  while(p1!=NULL){
      if(temp->Num<p1->Num){  
      temp->BranchNext=p1;
      if(p2==list&&p1==p2){
          list=temp;
        return list;
        }else
          p2->BranchNext=temp;
          return list;
    }
    else if(temp->Num>p1->Num){
         p2=p1;
         p1=p1->BranchNext;
         //当p1==NULL,下一步会跳出while循环,也可以放在while后 
         if(p1==NULL){
           temp->BranchNext=NULL;
           p2->BranchNext=temp;
        }
    }
  } 
  return list;
}
List InsertMain(List list,int x){ //(x/13代表花色,x%13代表大小)
  PtrToNode p1,p2,temp;        
  p1=p2=list;
  temp=malloc(sizeof(struct Poker));
  temp->Element=x;
  InitNode(temp);
  temp->mainNext=NULL;
  temp->BranchNext=NULL;
  //printf("\n%d=%d,%d",temp->Element,temp->Color,temp->Num);
  if(list==NULL){
    list=temp;
  }
  else
    while(p1!=NULL){
       if(temp->Color<p1->Color){        
            if(p2==list&&p1==p2){
          temp->mainNext=p1;
          list=temp;    
        }else{
             temp->mainNext=p1;
          p2->mainNext=temp;    
        }
        return list; 
       }else if(temp->Color==p1->Color){
           PtrToNode p3=p1->mainNext;
           PtrToNode p4=p1;
           PtrToNode p=InsertBranch(p1,x);
           p->mainNext=p3;
           if(p2==list&&p2==p4){
           list=p;      
         }else{
          p2->mainNext=p;          
           }
        return list;
        }else{
           p2=p1;
           p1=p1->mainNext;
           if(p1==NULL){
               temp->mainNext=NULL;
               temp->BranchNext=NULL; 
               p2->mainNext=temp;
           }
       }
    }//while结束 
  return list;
}
void printSingleList(List list){
    PtrToNode p1;
    p1=list;
    while(p1!=NULL){
        switch(p1->Color){
            case 0:printf("黑桃");break;
            case 1:printf("红桃");break;
            case 2:printf("梅花");break;
            case 3:printf("方块");break;
        }
        printf("%2d  ",p1->Num);
        p1=p1->BranchNext;
    }
}
void printDoubleList(List list){
    PtrToNode p=list;
    while(p!=NULL){
        switch(p->Color){
            case 0:printf("\n下面输出黑桃的数字排序:\n\t");break; 
            case 1:printf("\n下面输出红桃的数字排序:\n\t");break; 
            case 2:printf("\n下面输出梅花的数字排序:\n\t");break; 
            case 3:printf("\n下面输出方块的数字排序:\n\t");break; 
            default:printf("没有这个花色:\n");exit(0); 
        }
        printSingleList(p); 
        p=p->mainNext;
    }
}
void Warn(){
    printf("本程序的规定:\n");
    printf("\t1到13代表黑桃 14到26代表红桃 27到39代表梅花 40到52代表方块。\n\n" );
}
int main(){
    Warn();
    PtrToNode temp;
    int i;
    srand(time(NULL));
      int select[20];
      InitDisOrder(select);
    for(i=0;i<20;i++){
      temp=malloc(sizeof(struct Poker));    
      temp->Element=select[i];
      temp->BranchNext=NULL;
      InitNode(temp);
      printSingleList(temp);
      if((i+1)%10==0){
          printf("\n");    
        }    
    }
    List list=NULL;
    for(i=0;i<20;i++){
     list=InsertMain(list,select[i]);
    } 
    printDoubleList(list);
    printf("\n");
    return 0; 
} 

技术分享

      再先按大小后按花色排序:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

struct Poker{
  int Element;
  int Color;
  int Num; 
  struct Poker *mainNext;
  struct Poker *BranchNext;    
}; 
typedef struct Poker *List;
typedef struct Poker *PtrToNode;

void InitNode(PtrToNode p){
  if(p->Element%13==0){
      p->Num=13;
      p->Color=p->Element/13-1;
  }else{
      p->Num=p->Element%13;
      p->Color=p->Element/13;
  }
}  
//用数组辅助产生不重复的52以内的无序的整数20个包含52  
void InitDisOrder(int a[]){
  int s[52];
  int i,x;
  for(i=0;i<52;i++){
    s[i]=1;
  }
  for(i=0;i<20;i++){
L:  x=rand()%52;//产生1到52的随机数
    if(s[x]==0){
      goto L;
    }else{
      a[i]=x+1;
      s[x]=0;
    }    
  }
}
//用数组辅助产生不重复的有序的整数20个包括52 
void InitOrder(int a[]){
    int s[52];
    int i,j,x;
    for(i=0;i<52;i++){
      s[i]=1;    
    }
    for(i=0;i<20;i++){
L:        x=rand()%52;
        if(s[x]==0){
            goto L;
        }else
        s[x]=0;
    }
    for(i=0;i<52;i++){
      if(s[i]==0){
        a[j]=i+1;
        j++;        
      }else
      continue;
    }
}
PtrToNode InsertBranch(List list,int x){
  PtrToNode p1,p2,temp;
  p1=p2=list;
  temp=malloc(sizeof(struct Poker));
  temp->Element=x;
  temp->mainNext=NULL;
  temp->BranchNext=NULL;
  InitNode(temp);
  while(p1!=NULL){
      if(temp->Color<p1->Color){  
      temp->BranchNext=p1;
      if(p2==list&&p1==p2){
          list=temp;
        return list;
        }else
          p2->BranchNext=temp;
          return list;
    }
    else if(temp->Color>p1->Color){
         p2=p1;
         p1=p1->BranchNext;
         //当p1==NULL,下一步会跳出while循环,也可以放在while后 
         if(p1==NULL){
           temp->BranchNext=NULL;
           p2->BranchNext=temp;
        }
    }
  } 
  return list;
}
List InsertMain(List list,int x){ //(x/13代表花色,x%13代表大小)
  PtrToNode p1,p2,temp;        
  p1=p2=list;
  temp=malloc(sizeof(struct Poker));
  temp->Element=x;
  InitNode(temp);
  temp->mainNext=NULL;
  temp->BranchNext=NULL;
  //printf("\n%d=%d,%d",temp->Element,temp->Color,temp->Num);
  if(list==NULL){
    list=temp;
  }
  else
    while(p1!=NULL){
       if(temp->Num<p1->Num){        
            if(p2==list&&p1==p2){
          temp->mainNext=p1;
          list=temp;    
        }else{
             temp->mainNext=p1;
          p2->mainNext=temp;    
        }
        return list; 
       }else if(temp->Num==p1->Num){
           PtrToNode p3=p1->mainNext;
           PtrToNode p4=p1;
           PtrToNode p=InsertBranch(p1,x);
           p->mainNext=p3;
           if(p2==list&&p2==p4){
           list=p;      
         }else{
          p2->mainNext=p;          
           }
        return list;
        }else{
           p2=p1;
           p1=p1->mainNext;
           if(p1==NULL){
               temp->mainNext=NULL;
               temp->BranchNext=NULL; 
               p2->mainNext=temp;
           }
       }
    }//while结束 
  return list;
}
void printSingleList(List list){
    PtrToNode p1;
    p1=list;
    while(p1!=NULL){
        switch(p1->Color){
            case 0:printf("黑桃");break;
            case 1:printf("红桃");break;
            case 2:printf("梅花");break;
            case 3:printf("方块");break;
        }
        printf("%2d  ",p1->Num);
        p1=p1->BranchNext;
    }
}
void printDoubleList(List list){
    PtrToNode p=list;
    while(p!=NULL){
        printf("\n数字%d:\n\t",p->Num);
        printSingleList(p); 
        p=p->mainNext;
    }
}
void Warn(){
    printf("本程序的规定:\n");
    printf("\t1到13代表黑桃 14到26代表红桃 27到39代表梅花 40到52代表方块。\n" );
}

int main(){
    Warn();
    int i;
    srand(time(NULL));
      int select[20];
      PtrToNode temp;
      InitDisOrder(select);
    for(i=0;i<20;i++){
      printf("%3d=",select[i]);
      temp=malloc(sizeof(struct Poker));    
      temp->Element=select[i];
      temp->BranchNext=NULL;
      InitNode(temp);
      printSingleList(temp);
      if((i+1)%10==0){
          printf("\n");    
        }
    }
    List list=NULL;
    for(i=0;i<20;i++){
     list=InsertMain(list,select[i]);
    } 
    printDoubleList(list);
    return 0; 
} 

技术分享

      其实第二个程序只是第一个程序在条件上,顺序改了改,在做第一个时我考虑到了扩展性的问题,于是第二个程序只用了5分钟就完成了。而第一个程序用了几个小时。

 

数据结构与算法分析(5)表、栈和队列(一)

标签:

原文地址:http://www.cnblogs.com/MenAngel/p/5503476.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!