数据结构(c语言)第四章

           第四章 链表

4.1指针

指针最重要的两个运算符:
1)& 取地址运算符
2)* 复引用(或间址)运算符

4.1.1指针的危险性

当用c语言进行程序设计时,把所有不指向实际对象的指针设为NULL是一种明智的做法。
另一个明智的程序设计技巧是在进行指针类型之间相互转换时,显式地使用强制类型转换。

4.1.2动态存储分配

堆:在程序执行时进行存储分配。
例子:指针所指空间的分配和回收

int i,*pi;
float f,*pf;
pi=(int *)malloc(sizeof(int));
pf=(float *)malloc(sizeof(float));
*pi=1024;
*pf=3.14;
printf("an integer=%d,a float=%f\n",*pi,*pf);
free(pi);
free(pf);

malloc的返回结果是 void *;
当检查使用指针和动态存储分配的程序时,一定要保证,在不再使用动态存储区域时,将它归还给系统。

4.2单向链表

需要下列机制实现链式存储表示:
(1)一种定义结点结构的机制,结点结构含有所有的域。
(2)一种在需要时创建新结点的方法。
(3)一种删除不再需要的结点的方法。

例子:建立二结点的表

list_pointer create2()
{
  /*建立二结点的表*/
  list_pointer first,second;
  first=(list_pointer)malloc(sizeof(list_node));
  second=(list_pointer)malloc(sizeof(list_node));
  second->link=NULL;
  second->data=20;
  first->data=10;
  first->link=second;
  return first;
}

例子:在表的前端插入

void insert(list_pointer *ptr,list_pointer node)
{
   /*插入一个新结点的数据=50进入链表的头*/
   list_pointer temp;
   temp=(list_pointer)malloc(sizeof(list_node));
   if(IS_FULL(temp)){
      fprintf(stderr,"The memory is full\n");
      exit(1);
    }   
    temp->data=50;
    if(*ptr){
     temp->link=node->link;
     node->link=temp;
   }
   else{
     temp->link=NULL;
     *ptr=temp;
   }
}

例子:表的删除操作

void delete(list_pointer *ptr,list_pointer trail,list_pointer node)
{
  /*表的删除,trail是前面结点 ptr 也是头结点*/
  if(trail)
  trail->link=node->link;
  else
  *ptr=(*ptr)->link;
  free(node);
}

例子:表的输出

void print_list(list_pointer ptr)
{
  printf("The list contains: ");
  for(;ptr;ptr=ptr->link)
   printf("%4d",ptr->data);
   printf("\n");
}

4.3动态链栈与动态链队列

例子:栈链的插入

void add(stack_pointer *top, element item)
{
  /*添加一个数据到栈的头部*/
  stack_pointer temp=(stack_pointer)malloc(sizeof(stack));
  if(IS_FULL(temp)){
   fprintf(stderr,"The memory is full\n");
   exit(1);
  }
  temp->item=item;
  temp->link=*top;
  *top=temp;
}

例子:链栈的删除

element delete(stack_pointer *top){
  /*链栈的删除*/
  stack_pointer temp=*top;
  element item;
  if(IS_EMPTY(temp)){
   fprintf(stderr,"The stack is empty\n");
   exit(1);
  }
  item=temp->item;
  *top=temp->link;
  free(temp);
  return item;
}

例子:在链式队列的队尾的插入

void addq(queue_pointer *front,queue_pointer *rear,element item)
{
   /*在队列的尾部插入元素*/
   queue_pointer temp=(queue_pointer)malloc(sizeof(queue));
   if(IS_FULL(temp)){
    fprintf(stderr,"The memory is full\n");
    exit(1);
  }
  temp->item=item;
  temp->link=NULL;
  if(*front) (*rear)->link=temp;
  else *front=temp;
  *rear=temp;
}

例子:从链式队列的前端删除

element deleteq(queue_pointer *front)
{
  /*删除一个队列的元素*/
  queue_pointer temp=*front;
  element item;
  if(IS_EMPTY(*front)){
   fprintf(stderr,"The queue is empty\n");
   exit(1);
  }
  item=temp->item;
  *front=temp->link;
  free(temp);
  return item;
}

4.4多项式

4.4.1多项式的单向链表表示

4.4.2多项式加法

例子:两个多项式相加

poly_pointer padd(poly_pointer a,poly_pointer b)
{
 /*返回一个a加b的多项式*/
 poly_pointer front,rear,temp;
 int sum;
 rear=(poly_pointer)malloc(sizeof(poly_node));
 if(IS_FULL(rear)){
  fprintf(stderr,"The memory is full\n");
  exit(1);
  }
  front=rear;
  while(a&&b)
    switch(COMPARE(a->expon,b->expon)){
         case -1: /*a->expon<b->expon*/
                attach(b->coef,b->expon,&rear);
                b=b->link;
                break;
        case 0:/*a->expon=b->expon*/
               sum=a->coef+b->coef;
               if(sum) attach(sum,a->expon,&rear);
               a=a->link; b=b->link; break;
        case 1:/*a->expon>b->expon*/
                attach(a->coef,a->expon,&rear);
                a=a->link; 
   }
   /*复制剩下的链表a和链表b*/
   for(; a;a=a->link) attach(a->coef,a->expon,&rear);
   for(; b;b=b->link) attach(b->coef,b->expon,&rear);
   rea->link=NULL;
   /*删除其他的初始化结点*/
   temp=front; front=front->link; free(temp);
   return front;
}

例子:向表的尾端加入结点

void attach(float coefficient,int exponent,poly_pointer *ptr)
{
  /*创造一个新结点在 coef=coefficient and expon=exponent,添加它到ptr的头结点。ptr是更新点到这个新的结点*/
  poly_pointer temp;
  temp=(poly_pointer)malloc(sizeof(poly_node));
  if(IS_FULL(temp)){
   fprintf(stderr,"The memory is full\n");
   exit(1);
  }
  temp->coef=coefficient;
  temp->expon=exponent;
  (*ptr)->link=temp;
  *ptr=temp;
}

4.4.3多项式删除

链表非常适用于多项式操作。

例子:多项式删除

void erase(poly_pointer *ptr)
{
  /*删除多项式的点*/
  poly_pointer temp;
  while(*ptr){
  temp=*ptr;
  *ptr=(*ptr)->link;
  free(temp);
  }
}

4.4.4多项式的循环链表表示

如果修改表结构,使最后一个结点的链域指向表的首结点,那么,就可以更有效地释放多项式的所有结点。我们把它称为循环链表。最后结点的链域为空的单向链表称为
例子:函数get_node

poly_pointer get_node(void)
/*提供一个结点去使用*/
{
  poly_pointer node;
  if(avail){
   node=avail;
   avail=avail->link;
   }
   else{
      node=(poly_pointer)malloc(sizeof(poly_node));
      if(IS_FULL(node)){
           fprintf(stderr,"The memory is full\n");
           exit(1);
       }
   }
   return node;
}

例子:函数ret_node

void ret_node(poly_pointer ptr)
{
  /*返回一个结点到可利用的链表*/
  ptr->link=avail;
  avail=ptr;
}

例子:删除循环链表

void cerase(poly_pointer *ptr)
{
  /*删除循环链表*/
  poly_pointer temp;
  if(*ptr){
     temp=(*ptr)->link;
     (*ptr)->link=avail;
     avail=temp;
     *ptr=temp;
   }
}

例子:循环存储表示的多项式加法

poly_pointer cpadd(poly_pointer a,poly_pointer b)
{
  /*多项式a和b是单独链接循环列表和头结点一起。返回a的多项式,它是a和b的和*/
   poly_pointer starta,d,lastd;
   int sum,done=FALSE;
   starta=a; /*报告a的开始*/
   a=a->link; /*跳过头节点给a和b*/
   b=b->link; 
   d=get_node();  /*给和得到一个头结点*/
   d->expon=-1; lastd=d;
  do{
    switch(COMPARE(a->expon,b->expon)){
      case -1:/*a->expon<b->expon*/
             attach(b->coef,b->expon,&lastd);
             b=b->link;
             break;
       case 0:/*a->expon=b->expon*/
       if(starta==a) done=TRUE;
       else{
          sum=a->coef+b->coef;
          if(sum) attach(sum,a->expon,&lastd);
          a=a->link; b=b->link;
         }
         break;
        case 1:/*a->expon>b->expon*/
        attach(a->coef,a->expon,&lastd);
        a=a->link;
     }
  }while(!done)
  lastd->link=d;
  return d;
}

4.4.5小结

4.5链表的其他操作

4.5.1单向链表的操作

例子:翻转单链表

list_pointer invert(list_pointer lead)
{
  /*翻转单链表*/
  list_pointer middle,trail;
  middle=NULL;
  while(lead){
   trail=middle;
   middle=lead;
   lead=lead->link;
   middle->link=trail;
   }
   return middle;
}

例子:串接单链表

list_pointer concatenate(list_pointer ptr1,list_pointer ptr2)
{
  /*生成一个新链表包含链表1和链表2.链表暂时放在链表1*/
  list_pointer temp;
  if(IS_EMPTY(ptr1)) return ptr2;
  else{
   if(!IS_EMPTY(ptr2)){
      for(temp=ptr1;temp->link;temp=temp->link)
        ;
        temp->link=ptr2;
      }
      return ptr1;
   }
}

4.5.2循环链表的操作

例子:在表前端插入结点

void insert_front(list_pointer *ptr,list_pointer nodde)
/*插入结点到表ptr前,并且表ptr是表的最后一个结点*/
{
  if(IS_EMPTY(*ptr)){
   /*表是空,改变ptr到点的入口*/
   *ptr=node;
   node->link=node;
   }
   else{
   /*表不是空的,新入口在前面*/
   node->link=(*ptr)->link;
   (*ptr)->link=node;
   }
}

例子:求循环链表的长度

int length(list_pointer ptr)
{
  /*发现循环链表ptr的长度*/
  list_pointer temp;
  int count=0;
  if(ptr){
       temp=ptr;
       do{
       count++;
       temp=temp->link;
        }while(temp!=ptr);
   }
   return count;
}

4.6等价关系

定义:集合S上的关系=,称为S上等价关系,当且仅当它在S上是对称的,自反的,传递的。

例子:等价算法的第一次求精

void equivalence()
{
   initialize;
   while(there are more pairs){
       read the next pair<i,j>;
       process this pair;
    }
    initialize the output;
    do
      output a new equivalence class;
      while(not done);
}

例子:较详细的等价算法

void equivalence()
{
   initialize seq to NULL and out to TRUE;
   while(there are more pairs){
   read the next pair,<i,j>;
   put j on the seq[i] list;
   put i on the seq[j] list;
    }
    for(i=0;i<n;i++)
    if(out[i]){
      out[i]=FALSE;
      output this equivalence class;
   }
}

例子:寻找等价类的程序

#include<stdio.h>
#include<alloc.h>
#define MAX_SIZE 24
#define IS_FULL(ptr) (!(ptr))
#define  FALSE 0
#define TRUE 1
typedef struct node *node_pointer;
typedef struct node{
     int data;
     node_pointer link;
}
void main(void)
{
    short int out[MAX_SIZE];
    node_pointer seq[MAX_SIZE];
    node_pointer x,y,top;
    int i,j,n;
    printf("Enter the size(<=%d)",MAX_SIZE);
    scanf("%d",&n);
    for(i=0;i<n;i++){
        /*初始化seq和out*/
        out[i]=TRUE;  seq[i]=NULL;
    }
    /*阶段 1:输入等价对: */
    printf("Enter a pair of numbers (-1 -1 to quit): ");
    scanf("%d%d",&i,&j);
    while(i>=0){
        x=(node_pointer)malloc(sizeof(node));
        if(IS_FULL(x)){
            fprintf(stderr,"The memory is full\n");
            exit(1);
        }
        x->data=j; x->link=seq[i];  seq[i]=x;
        x=(node_pointer)malloc(sizeof(node));
        if(IS_FULL(x)){
            fprintf(stderr,"The memory is full\n");
            exit(1);
        }
        x->data=i; x->link=seq[j]; seq[j]=x;
        printf("Enter a pair of numbers (-1 -1 to quit): ");
        scanf("%d%d",&i,&j);
    }
    /*阶段 2:输出等价类*/
    for(i=0;i<n;i++)
    if(out[i]){
        printf("\nNew class: %5d",i);
        out[i]=FALSE; /*将类设置为假*/
        x=seq[i]; top=NULL; /*初始化栈*/
        for(;;){  /*查找其他类内容*/
            while(x){  /*进程列表*/
                j=x->data;
                if(out[j]){
                    printf("%5d",j);  out[j]=FALSE;
                    y=x->link; x->link=top; top=x; x=y;
                }
                else x=x->link;
            }
            if(!top) break;
            x=seq[top->data]; top=top->link; /*无栈*/
        }
    }
}

4.7稀疏矩阵

例子:读取稀疏矩阵

matrix_pointer mread(void)
{
    /*在矩阵中读取并设置其链接表示.使用辅助全局阵列 hdnode*/
    int num_rows,num_cols,num_terms,num_heads,i;
    int row,col,value,current_row;
    matrix_pointer temp,last,node;
    printf("Enter the number of rows,columns and number of nonzero terms: ");
    scanf("%d%d%d",&num_rows,&num_cols,&num_terms);
    num_heads=(num_cols>num_rows)?num_cols:num_rows;
    /*为头节点列表设置头节点*/
    node=new_node(); node->tag=entry;
    node->u.entry.row=num_rows;
    node->u.entry.col=num_cols;
    if(!num_heads) node->right=node;
    else { /*初始化头结点*/
        for(i=0;i<num_heads;i++){
            temp=new_node;
            hdnode[i]=temp; hdnode[i]->tag=head;
            hdnode[i]->right=temp; hdnode[i]->u.next=temp;
        }
        current_row=0;
        last=hdnode[0];  /*当前行中的最后一个节点*/
        for(i=0i<num_terms;i++){
            printf("Enter row,colums and value: ");
            scanf("%d%d%d",&row,&col,&value);
            if(row>current_row){ /*关闭当前行*/
                last->right=hdnode[current_row];
                current_row=row; last=hdnode[row];
            }
            temp=new_node();
            temp->tag=entry; temp->u.entry.row=row;
            temp->u.entry.col=col;
            temp->u.entry.value=value;
            last->right=temp; /*链接到行列表*/
            last=temp;
            /*链接到列列表*/
            hdnode[col]->u.next->down=temp;
            hdnode[col]->u.next=temp;
        }
        /*关闭最后一行*/
        last->right=hdnode[current_row];
        /*关闭所有列列表*/
        for(i=0;i<num_cols;i++)
            hdnode[i]->u.next->down=hdnode[i];
        /*将所有头节点链接在一起*/
        for(i=0;i<num_heads-1;i++)
            hdnode[i]->u.next=hdnode[i+1];
        hdnode[num_heads-1]->u.next=node;
        node->right=hdnode[0];
    }
    return node;
}

例子:获得矩阵的新结点

matrix_pointer new_node(void)
{
   matrix_pointer temp;
   temp=(matrix_pointer)malloc(sizeof(matrix_node));
   if(IS_FULL(temp)){
     fprintf(stderr,"The memory is full\n");
     exit(1);
   }
   return temp;
}

例子:输出稀疏矩阵

 void mwrite(matrix_pointer node)
 {
   /*以行主要形式打印出矩阵*/
   int i;
   matrix_pointer temp,head=node->right;
   /*矩阵尺寸*/
   printf(" \n num_rows=%d,num_cols=%d \n",node->u.entry.row,node->u.entry.col);
   printf("The matrix by row,column,and value: \n\n");
   for(i=0;i<node->u.entry.row;i++){
         /*打印出每行中的条目*/
         for(temp=head->right;temp!=head;temp=temp->right)
         printf("%5d%5d%5d \n",temp->u.entry.row,temp->->u.entry.col,temp->u.entry.value);
         head=head->u.next; /*下一行*/
    }
 }

例子:删除稀疏矩阵

void merase(matrix_pointer *node)
{
   /*删除矩阵,将节点返回到堆*/
   matrix_pointer x,y, head=(*node)->right;
   int i,num_heads;
   /*按行释放入口节点和头节点*/
   for(i=0;i<(*node)->u.entry.row;i++){
    y=head->right;
    while(y!=head){
       x=y; y=y->right; free(x);
    }
    x=head; head=head->u.next; free(x);
  }
  /*释放剩余的头节点*/
  y=head;
  while(y!=*node){
   x=y; y=y->u.next; free(x);
   }
   free(*node); *node=NULL;
}

4.8双向链表

例子:双向循环链表的插入操作

 void dinsert(node_pointer node,node_pointer newnode)
 {
   /*在节点右侧插入新节点*/
   newnode->1link=node;
   newnode->rlink=node->rlink;
   node->rlink->1link=newnode;
   node->rlink=newnode;
 }

例子:双向循环链表的删除操作

void ddelete(node_pointer node,node_pointer deleted)
{
   /*从双链表中删除*/
   if(node==deleted)
   printf("Deletion of head node not permitted.\n");
   else{
    deleted->1link->rlink=deleted->rlink;
    deleted->rlink->1link=deleted->1link;
    free(deleted);
   }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值