Data-Structure 之二

第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;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
posted @ 2011-01-18 17:49  yangzd  阅读(381)  评论(1编辑  收藏  举报