第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; |          
                     | } |