第3章 线性表的链式存储
    3.1链式存储
      数据结构的存储方式必须体现它的逻辑关系 。在链式存储方式下,实现中除存放一个结点的信息外,还需附设指针,用指针体现结点之间的逻辑关系。如果一个结点有多个后继或多个前驱,那么可以附设相应个数的指针,一个结点附设的指针指向的是这个结点的某个前驱或后继。
    3.2单链表
      结点一般含有两个域,一个是存放数据信息的info域,另一个是指向该结点的后继结点的存放地址的指针域next。一个单链表必须有一个首指针指向单链表中的第一个结点。
                              | ADT link_list{ | 
                     | 数据集合K:K={k1, k2,…, kn},n≥0,K中的元素是datatype | 
                     | 类型数据关系R:R={r} | 
                     | r={ <ki, ki+1>| i=1,2,…,n-1} | 
                     | 操作集合: | 
                     | (1) node *init_link_list() 建立一个空的单链表 | 
                     | (2) void print_link_list(node *head) 输出单链表中各个结点的值 | 
                     | (3) node *insert_in_front_link_list(node *head,datatype x)  插入一个值为x的结点作为单链表的第一个结点 | 
                     | (4) node *find_num_link_list(node *head,datatype x) 在单链表中查找一个值为x的结点 | 
                     | (5) node *find_pos_link_list(node *head,int i) 在单链表中查找第i个结点 | 
                     | (6) node *insert_x_after_y(node *head,datatype x,datatype y) 在单链表中值为y的结点后插入一个值为x的新结点 | 
                     | (7) node *insert_x_after_i(node *head,datatype x,int i) 在单链表中第i个结点后插入一个值为x的新结点 | 
                     | (8) node *delete_num_link_list(node *head,datatype x) 在单链表中删除一个值为x的结点 | 
                     | (9) node *delete_pos_link_list(node *head,int i) 在单链表中删除第i个结点 | 
                     | }ADT link_list; | 
       
     
   
                              | // slnklist.h | 
                     |  | 
                     | typedef int datatype; | 
                     | typedef struct link_node{ | 
                     | datatype info; | 
                     | struct link_node *next; | 
                     | }node; | 
       
     
                              | // 建立一个空的单链表 | 
                     |  | 
                     | node *init_link_list() | 
                     | { | 
                     | return NULL; | 
                     | } | 
       
     
                              | // slnkprin.c | 
                     |  | 
                     | void print_link_list(node *head) | 
                     | { | 
                     | node *p; | 
                     |  | 
                     | p=head; | 
                     | if(!p) | 
                     | printf("\nslinklist is empty!"); | 
                     | else | 
                     | { | 
                     | printf("\neach value of node is:\n"); | 
                     | while(p) | 
                     | { | 
                     | printf("%5d",p->info); | 
                     | p=p->next; | 
                     | } | 
                     | } | 
                     | } | 
       
     
                              | // 查找一个值为x的结点 | 
                     |  | 
                     | node *find_num_link_list(node *head,datatype x) | 
                     | { | 
                     | node *p; | 
                     |  | 
                     | p=head; | 
                     | while(p&&p->info!=x) | 
                     | p=p->next; | 
                     |  | 
                     | return p; | 
                     | } | 
       
     
                              | // 查找第i个结点 | 
                     |  | 
                     | node *find_pos_link_list(node *head,int i) | 
                     | { | 
                     | int j=1; | 
                     | node *p=head; | 
                     |  | 
                     | if(i<1) | 
                     | { | 
                     | printf("\nError!\n"); | 
                     | exit(1); | 
                     | } | 
                     | while(p&&i!=j) | 
                     | { | 
                     | p=p->next; | 
                     | j++; | 
                     | } | 
                     | return p; | 
                     | } | 
       
     
                              | // 插入一个值为x的结点作为单链表的第一个结点 | 
                     |  | 
                     | node *insert_in_front_link_list(node *head,datatype x) | 
                     | { | 
                     | node *p; | 
                     | p=(node*)malloc(sizeof(node)); /*分配空间*/ | 
                     | p->info=x;                     /*设置新结点的值*/ | 
                     | p->next=head;                  /*插入(1)*/ | 
                     | head=p;                        /*插入(2)*/ | 
                     | return head; | 
                     | } | 
       
     
                              | // 在单链表中第i个结点后插入一个值为x的新结点 | 
                     |  | 
                     | node *insert_x_after_i(node *head,datatype x,int i) | 
                     | { | 
                     | node *p,*q; | 
                     |  | 
                     | q=find_pos_link_list(head,i);/*查找第i个结点*/ | 
                     | if(!q) | 
                     | { | 
                     | printf("\ncan't find node %d, can't insert!\n",i); | 
                     | exit(1); | 
                     | } | 
                     | p=(node*)malloc(sizeof(node));/*分配空间*/ | 
                     | p->info=x;                    /*设置新结点*/ | 
                     | p->next=q->next;              /*插入(1)*/ | 
                     | q->next=p;                    /*插入(2)*/ | 
                     |  | 
                     | return head; | 
                     | } | 
       
     
                              | // 删除一个值为x的新结点 | 
                     |  | 
                     | node *delete_num_link_list(node *head,datatype x) | 
                     | { | 
                     | node *pre=NULL,*p; | 
                     | if(!head) | 
                     | { | 
                     | printf("\nthe slinklist is empty!\n"); | 
                     | return head; | 
                     | } | 
                     | p=head; | 
                     | while(p&&p->info!=x)/*没有找到并且没有找完*/ | 
                     | { | 
                     | pre=p;p=p->next;}/*pre指向p的前驱结点*/ | 
                     | if(!pre&&p->info==x)/*要删除的是第一个结点*/ | 
                     | head=head->next;/*删除(1)*/ | 
                     | else | 
                     | pre->next=p->next; | 
                     | free(p); | 
                     |  | 
                     | return head; | 
                     | } | 
       
     
   
    3.3带头结点单链表
      一般的单链表中,第一个结点由head指示,而在带头结点单链表中,head指示的是所谓的头结点,它不是存储数据结构中的实际结点,第一个实际的结点是head->next指示的。在带头结点单链表的操作实现时要注意这一点。
                              | ADT hlink_list | 
                     | { | 
                     | 数据集合K:K={k1, k2,…, kn},n≥0,K中的元素是datatype类型 | 
                     | 数据关系R:R={r} | 
                     | r={ <ki, ki+1>| i=1,2,…,n-1} | 
                     | 操作集合: | 
                     | (1) node *init_hlink_list()  建立一个空的带头结点的单链表 | 
                     | (2) void print_hlink_list(node *head)  输出带头结点单链表中各个结点的值 | 
                     | (3) node *find_num_hlink_list(node *head,datatype x)   在带头结点单链表中查找一个值为x的结点 | 
                     | (4) node *find_pos_hlink_list(node *head,int i)  在带头结点单链表中查找第i个结点 | 
                     | (5) node *insert_in_front_hlink_list(node *head,datatype x)   插入一个值为x的结点作为带头结点单链表的第一个结点 | 
                     | (6) node *insert_x_after_y(node *head,datatype x,datatype y)   在带头结点单链表中值为y的结点后插入一个值为x的新结点 | 
                     | (7) node *insert_x_after_i(node *head,datatype x,int i)   在带头结点单链表中第i个结点后插入一个值为x的新结点 | 
                     | (8) node *delete_num_hlink_list(node *head,datatype x)   在带头结点单链表中删除一个值为x的结点 | 
                     | (9) node *delete_pos_hlink_list(node *head,int i)   在带头结点单链表中删除第i个结点 | 
                     | }ADT hlink_list; | 
       
     
   
                              | // 建立一个空的带头结点单链表 | 
                     |  | 
                     | node *init_hlink_list() | 
                     | { | 
                     | node *head; | 
                     |  | 
                     | head=(node*)malloc(sizeof(node)); | 
                     | head->next=NULL; | 
                     |  | 
                     | return head; | 
                     | } | 
       
     
                              | // 输出带头结点单链表中各个结点的值 | 
                     |  | 
                     | void print_hlink_list(node *head) | 
                     | { | 
                     | node *p; | 
                     |  | 
                     | p=head->next;/*从第一个(实际)结点开始*/ | 
                     | if(!p) | 
                     | printf("\n带头结点单链表是空的!"); | 
                     | else | 
                     | { | 
                     | printf("\n带头结点的单链表各个结点的值为:\n"); | 
                     | while(p) | 
                     | { | 
                     | printf("%5d",p->info); | 
                     | p=p->next; | 
                     | } | 
                     | } | 
                     | } | 
       
     
                              | // 在带头结点单链表中查找一个值为x的结点 | 
                     |  | 
                     | node *find_num_hlink_list(node *head,datatype x) | 
                     | { | 
                     | node *p; | 
                     |  | 
                     | p=head->next;/*从第一个(实际)结点开始*/ | 
                     | while(p&&p->info!=x) | 
                     | p=p->next; | 
                     |  | 
                     | return p; | 
                     | } | 
       
     
                              | // 在带头结点单链表中查找第i个结点 | 
                     |  | 
                     | node *find_pos_hlink_list(node *head,int i) | 
                     | { | 
                     | int j=0; | 
                     | node *p=head; | 
                     |  | 
                     | if(i<0) | 
                     | { | 
                     | printf("\n带头结点的单链表中不存在第%d个结点!",i); | 
                     | return NULL; | 
                     | } | 
                     | while(p&&i!=j)/*没有查找完并且还没有找到*/ | 
                     | { | 
                     | p=p->next; | 
                     | j++;/*继续向后(左)查找,计数器加1*/ | 
                     | } | 
                     |  | 
                     | return p;/*返回结果,i=0时,p指示的是头结点*/ | 
                     | } | 
       
     
                              | // 在带头结点单链表中值为y的结点后插入一个值为x的新结点 | 
                     |  | 
                     | node *insert_x_after_y(node *head,datatype x,datatype y) | 
                     | { | 
                     | node *p,*q; | 
                     |  | 
                     | q=find_num_hlink_list(head,y);/*查找值为y的结点*/ | 
                     | if(!q)/*没有找到*/ | 
                     | { | 
                     | printf("\n没有找到值为%d的结点,不能插入%d!",y,x); | 
                     | return head; | 
                     | } | 
                     | p=(node*)malloc(sizeof(node));/*为准备插入的新结点分配空间*/ | 
                     | p->info=x;/*为新结点设置值x*/ | 
                     | p->next=q->next;/*插入(1)*/ | 
                     | q->next=p;/*插入(2)*/ | 
                     |  | 
                     | return head; | 
                     | } | 
       
     
                              | // 在带头结点单链表中删除一个值为x的结点 | 
                     |  | 
                     | node *delete_num_hlink_list(node *head,datatype x) | 
                     | { | 
                     | node *pre=head,*q;/*首先pre指向头结点*/ | 
                     | q=head->next;/*q从带头结点的第一个实际结点开始找值为x的结点*/ | 
                     | while(q&&q->info!=x)/*没有查找完并且还没有找到*/ | 
                     | { | 
                     | pre=q; | 
                     | q=q->next; | 
                     | }/*继续查找,pre指向q的前驱*/ | 
                     | pre->next=q->next;/*删除*/ | 
                     | free(q);/*释放空间*/ | 
                     |  | 
                     | return head; | 
                     | } | 
       
     
   
    3.4循环单链表
      对于一个循环单链表,若首指针为head,表中的某个结点p是最后一个结点的特征应该是p->next==head。
      循环单链表的头文件和单链表的相同。
                              | // 建立一个空的循环单链表 | 
                     |  | 
                     | node *init_clink_list() | 
                     | { | 
                     | return NULL; | 
                     | } | 
       
     
                              | // 输出循环单链表中各个结点的值 | 
                     |  | 
                     | void print_clink_list(node *head) | 
                     | { | 
                     | node *p; | 
                     |  | 
                     | if(!head) | 
                     | printf("\n循环单链表是空的!\n"); | 
                     | else | 
                     | { | 
                     | printf("\n循环单链表各个结点的值分别为:\n"); | 
                     | printf("%5d",head->info);/*输出非空表中第一个结点的值*/ | 
                     | p=head->next;/*p指向第一个结点的下一个结点*/ | 
                     | while(p!=head)/*没有回到第一个结点*/ | 
                     | { | 
                     | printf("%5d",p->info); | 
                     | p=p->next; | 
                     | } | 
                     | } | 
                     | } | 
       
     
                              | // 在循环单链表中第i个结点后插入一个值为x的新结点 | 
                     |  | 
                     | node *insert_x_after_i(node *head,datatype x,int i) | 
                     | { | 
                     | node *p,*q; | 
                     |  | 
                     | q=find_pos_clink_list(head,i);/*查找第i个结点,q指向第i个结点*/ | 
                     | if(!q)/*没有找到,则不进行插入*/ | 
                     | printf("\n表中不存在第%d个结点,无法进行插入!\n",i); | 
                     | else | 
                     | {   /*找到了第i个结点,准备插入x*/ | 
                     | p=(node*)malloc(sizeof(node));/*分配空间*/ | 
                     | p->info=x;/*设置新结点的值*/ | 
                     | p->next=q->next;/*插入,修改指针(1)*/ | 
                     | q->next=p;/*插入,修改指针(2)*/ | 
                     | } | 
                     |  | 
                     | return head; | 
                     | } | 
       
     
                              | // 在循环单链表中删除一个值为x的结点 | 
                     |  | 
                     | node *delete_num_clink_list(node *head,datatype x) | 
                     | { | 
                     | node *pre=NULL,*q;/*q用于查找值为x的结点,pre指向q的前驱结点*/ | 
                     |  | 
                     | if(!head)/*表为空,则无法做删除操作*/ | 
                     | { | 
                     | printf("\n循环单链表为空,无法做删除操作!"); | 
                     | return NULL; | 
                     | } | 
                     | q=head;/*从第1个结点开始准备查找*/ | 
                     | while(q->next!=head&&q->info!=x)/*没有找遍整个表并且没有找到*/ | 
                     | { | 
                     | pre=q; | 
                     | q=q->next;/*pre为q的前驱,继续查找*/ | 
                     | }/*循环结束后,pre为q的前驱*/ | 
                     | if(q->info!=x)/*没找到*/ | 
                     | { | 
                     | printf("没有找到值为%d的结点!",x); | 
                     | } | 
                     | else   /*找到了,下面要删除q*/ | 
                     | { | 
                     | pre->next=q->next;/*删除q指向的结点*/ | 
                     | free(q);/*释放空间*/ | 
                     | } | 
                     |  | 
                     | return head; | 
                     | } | 
       
     
   
     3.5双链表
                              | // 双链表的头文件 | 
                     |  | 
                     | typedef int datatype; | 
                     | typedef struct dlink_node{ | 
                     | datatype info; | 
                     | struct dlink_node *llink,*rlink; | 
                     | }dnode; | 
       
     
                              | // 输出双链表中各个结点的值 | 
                     |  | 
                     | void print_dlink_list(dnode *head) | 
                     | { | 
                     | dnode *p; | 
                     |  | 
                     | p=head; | 
                     | if(!p) | 
                     | printf("\n双链表是空的!\n"); | 
                     | else | 
                     | { | 
                     | printf("\n双链表中各个结点的值为:\n"); | 
                     | while(p) | 
                     | { | 
                     | printf("%5d",p->info); | 
                     | p=p->rlink; | 
                     | } | 
                     | } | 
                     | } | 
       
     
                              | // 查找双链表中第i个结点 | 
                     |  | 
                     | dnode *find_pos_dlink_list(dnode *head,int i) | 
                     | { | 
                     | int j=1; | 
                     | dnode *p=head; | 
                     |  | 
                     | if(i<1) | 
                     | { | 
                     | printf("\n第%d个结点不存在!\n",i); | 
                     | return NULL; | 
                     | } | 
                     | while(p&&i!=j)/*没有找完整个表并且没有找到*/ | 
                     | { | 
                     | p=p->rlink;j++;/*继续沿着右指针向后查找,计数器加1*/ | 
                     | } | 
                     | if(!p) | 
                     | { | 
                     | printf("\n第%d个结点不存在!\n",i); | 
                     | return NULL; | 
                     | } | 
                     |  | 
                     | return p; | 
                     | } | 
       
     
                              | // 在双链表中第i个结点后插入一个值为x的新结点 | 
                     |  | 
                     | dnode *insert_x_after_i(dnode *head,datatype x,int i) | 
                     | { | 
                     | dnode *p,*q; | 
                     |  | 
                     | p=(dnode*)malloc(sizeof(dnode));/*分配空间*/ | 
                     | p->info=x;/*设置新结点的值*/ | 
                     | if(i==0)/*在最前面插入一个值为x的新结点*/ | 
                     | { | 
                     | p->llink=NULL;/*新插入的结点没有前驱*/ | 
                     | p->rlink=head;/*新插入的结点的后继是原来双链表中的第一个结点*/ | 
                     | head=p;/*新结点成为双链表的第一个结点*/ | 
                     | return head; | 
                     | } | 
                     | q=find_pos_dlink_list(head,i);/*查找第i个结点*/ | 
                     | if(!q)/*第i个结点不存在*/ | 
                     | { | 
                     | printf("第%d个结点不存在,无法进行插入",i); | 
                     | return head; | 
                     | } | 
                     | if(q->rlink==NULL)/*在最后一个结点后插入*/ | 
                     | { | 
                     | p->rlink=q->rlink;/*即为NULL,新插入的结点没有后继。插入操作(1)*/ | 
                     | p->llink=q;/*插入操作(2)*/ | 
                     | q->rlink=p;/*插入操作(4)*/ | 
                     | }/*注意不能和下面的一般情况一样处理,这里如执行下面的(3)将出错!*/ | 
                     | else/*一般情况下的插入*/ | 
                     | { | 
                     | p->rlink=q->rlink;/*插入操作(1)*/ | 
                     | p->llink=q;/*插入操作(2)*/ | 
                     | q->rlink->llink=p;/*插入操作(3)*/ | 
                     | q->rlink=p;/*插入操作(4)*/ | 
                     | } | 
                     |  | 
                     | return head; | 
                     | } | 
       
     
                              | // 在双链表中删除一个值为x的结点 | 
                     |  | 
                     | dnode *delete_num_dlink_list(dnode *head,datatype x) | 
                     | { | 
                     | dnode *q; | 
                     |  | 
                     | if(!head)/*双链表为空,无法进行删除操作*/ | 
                     | { | 
                     | printf("双链表为空,无法进行删除操作"); | 
                     | return head; | 
                     | } | 
                     | q=head; | 
                     | while(q&&q->info!=x) | 
                     | q=q->rlink;/*循环结束后q指向的是值为x的结点*/ | 
                     | if(!q) | 
                     | { | 
                     | printf("\n没有找到值为%d的结点!不做删除操作!",x); | 
                     | } | 
                     | if(q==head&&head->rlink)/*被删除的结点是第一个结点并且表中不只一个结点*/ | 
                     | { | 
                     | head=head->rlink; | 
                     | head->llink=NULL; | 
                     | free(q);return head; | 
                     | } | 
                     | if(q==head&&!head->rlink)/*被删除的结点是第一个结点并且表中只有这一个结点*/ | 
                     | { | 
                     | free(q); | 
                     | return NULL;/*双链表置空*/ | 
                     | } | 
                     | else | 
                     | { | 
                     | if(!q->rlink)/*被删除的结点是双链表中的最后一个结点*/ | 
                     | { | 
                     | q->llink->rlink=NULL; | 
                     | free(q); | 
                     | return head; | 
                     | } | 
                     | else/*q是在一个有2个以上结点的双链表中的一个非开始、也非终端结点*/ | 
                     | { | 
                     | q->llink->rlink=q->rlink; | 
                     | q->rlink->llink=q->llink; | 
                     | free(q); | 
                     | return head; | 
                     | } | 
                     | } | 
                     | } | 
       
     
   
     3.6链式栈
      栈的链式存储称为链式栈。链式栈就是一个特殊的单链表,对于这特殊的单链表,它的插入和删除规定在单链表的同一端进行。链式栈的栈顶指针一般用top表示。
      链式栈类型的描述如下:
                              | ADT link_stack{ | 
                     | 数据集合K:K={k1, k2,…, kn},n≥0,K中的元素是datatype类型 | 
                     | 数据关系R:R={r} | 
                     | r={ <ki, ki+1>| i=1,2,…,n-1} | 
                     | 操作集合: | 
                     | (1) node *init_link_stack() 建立一个空链式栈 | 
                     | (2) int empty_link_stack(node *top) 判断链式栈是否为空 | 
                     | (3) datatype get_top(node *top) 取得链式栈的栈顶结点值 | 
                     | (4) void print_link_stack(node *top) 输出链式栈中各个结点的值 | 
                     | (5) node *push_link_stack(node *top,datatype x) 向链式栈中插入一个值为x的结点 | 
                     | (6) node *pop_link_stack(node *top)  删除链式栈的栈顶结点 | 
                     | }ADT link_stack; | 
       
     
   
                              | // 取得链式栈的栈顶结点值 | 
                     |  | 
                     | datatype get_top(node *top) | 
                     | { | 
                     | if(!top) | 
                     | { | 
                     | printf("\n链式栈是空的!"); | 
                     | exit(1); | 
                     | } | 
                     | return(top->info); | 
                     | } | 
       
     
                              | // 判断链式栈是否为空 | 
                     |  | 
                     | int empty_link_stack(node *top) | 
                     | { | 
                     | return (top? 0:1); | 
                     | } | 
       
     
                              | // 输出链式栈中各个结点的值 | 
                     |  | 
                     | void print_link_stack(node *top) | 
                     | { | 
                     | node *p; | 
                     |  | 
                     | p=top; | 
                     | if(!p) printf("\n链式栈是空的!"); | 
                     | while(p) | 
                     | { | 
                     | printf("%5d",p->info); | 
                     | p=p->next; | 
                     | } | 
                     | } | 
       
     
                              | // 向链式栈中插入一个值为x的结点 | 
                     |  | 
                     | node *push_link_stack(node *top,datatype x) | 
                     | { | 
                     | node *p; | 
                     |  | 
                     | p=(node*)malloc(sizeof(node)); /*分配空间*/ | 
                     | p->info=x;                     /*设置新结点的值*/ | 
                     | p->next=top;                   /*插入(1)*/ | 
                     | top=p;                         /*插入(2)*/ | 
                     | return top; | 
                     | } | 
       
     
                              | // 删除链式栈的栈顶结点 | 
                     |  | 
                     | node *pop_link_stack(node *top) | 
                     | { | 
                     | node *q; | 
                     |  | 
                     | if(!top) | 
                     | { | 
                     | printf("\n链式栈是空的!"); | 
                     | return NULL; | 
                     | } | 
                     | q=top;/*指向被删除的结点(1)*/ | 
                     | top=top->next;/*删除栈顶结点(2)*/ | 
                     | free(q); | 
                     | return top; | 
                     | } | 
       
     
   
    3.7链式队列
      队列的链式存储称为链式队列。链式队列就是一个特殊的单链表,对于这种特殊的单链表,它的插入和删除规定在单链表的不同端进行。链式队列的队首和队尾指针分别用front和rear表示。
      链式队列类型的描述如下:
                              | ADT link_queue{ | 
                     | 数据集合K:K={k1, k2,…, kn},n≥0,K中的元素是datatype类型 | 
                     | 数据关系R:R={r} | 
                     | r={ <ki, ki+1>| i=1,2,…,n-1} | 
                     | 操作集合: | 
                     | (1) queue *init_link_queue() 建立一个空的链式队列 | 
                     | (2) int empty_link_queue(queue qu) 判断链式队列是否为空 | 
                     | (3) void print_link_queue(queue *qu) 输出链式队列中各个结点的值 | 
                     | (4) datatype get_first(queue qu) 取得链式队列的队首结点值 | 
                     | (5) queue *insert_link_queue(queue *qu,datatype x) 向链式队列中插入一个值为x的结点 | 
                     | (6) queue *delete_link_queue(queue *qu) 删除链式队列中队首结点 | 
                     | }ADT link_queue; | 
       
     
   
      链式队列的结点定义必须有队首和队尾指针,因此增加定义一个结构类型,其中的两个域分别为队首和队尾指针。其定义如下:
                              | typedef struct{ | 
                     | node *front,*rear;  /*定义队首与队尾指针*/ | 
                     | }queue; | 
       
     
   
                              | // 建立一个空的链式队列 | 
                     |  | 
                     | queue *init_link_queue() | 
                     | { | 
                     | queue *qu; | 
                     |  | 
                     | qu=(queue*)malloc(sizeof(queue));  /*分配空间*/ | 
                     | qu->front=NULL;    /*队首指针设置为空*/ | 
                     | qu->rear=NULL;     /*队尾指针设置为空*/ | 
                     | return qu; | 
                     | } | 
       
     
      
                             | // 取得链式队列的队首结点值 | 
                     |  | 
                     | datatype get_first(queue qu) | 
                     | { | 
                     | if(!qu.front) | 
                     | { | 
                     | printf("\n链式队列是空的!"); | 
                     | exit(1); | 
                     | } | 
                     | return(qu.front->info); | 
                     | } | 
       
     
                              | // 向链式队列中插入一个值为x的结点 | 
                     |  | 
                     | queue *insert_link_queue(queue *qu,datatype x) | 
                     | { | 
                     | node *p; | 
                     |  | 
                     | p=(node*)malloc(sizeof(node)); /*分配空间*/ | 
                     | p->info=x;   /*设置新结点的值*/ | 
                     | p->next=NULL; | 
                     | if(qu->front==NULL) | 
                     | qu->front=qu->rear=p; | 
                     | else | 
                     | { | 
                     | qu->rear->next=p;    /*队尾插入*/ | 
                     | qu->rear=p; | 
                     | } | 
                     | return qu; | 
                     | } | 
       
     
                              | // 删除队首结点 | 
                     |  | 
                     | queue *delete_link_queue(queue *qu) | 
                     | { | 
                     | node *q; | 
                     | if(!qu->front) | 
                     | { | 
                     | printf("队列为空,无法删除!"); | 
                     | return qu; | 
                     | } | 
                     | q=qu->front;   /*q指向队首结点(1)*/ | 
                     | qu->front=q->next; /*队首指针指向下一个结点(2)*/ | 
                     | free(q);       /*释放原队首结点空间*/ | 
                     | if(qu->front==NULL) | 
                     | qu->rear=NULL;    /*队列中的唯一结点被删除后,队列变空(3)*/ | 
                     | return qu; | 
                     | } |