C语言描述:链式线性表

单链表基本操作

链表的创立

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

struct NODE{
	int data;
	struct NODE* next;

};

struct NODE* Creatlink(void);
void OutPutLink(struct NODE* head);

int main(void){
      struct NODE* head;
      head=Creatlink();
      OutPutLink(head);

		return 0;

}
struct NODE* Creatlink(void){
      int len,i,val;
      struct NODE* head=malloc(sizeof*head);
      struct NODE* move=head;

      move->next=NULL;
      if(head==NULL){
            printf("分配内存失败");
            exit(-1);
      }

      printf("你要输入几个结点:");
      scanf("%d",&len);

      for(i=0;i<len;i++){
            struct NODE* fresh=malloc(sizeof*fresh);
            if(fresh==NULL){
                  printf("分配内存失败");
                  exit(-1);
            }
            printf("请输入第%d个结点",i+1);
            scanf("%d",&val);
            fresh->data=val;

            move->next=fresh;
            fresh->next=NULL;
            move=fresh;

      }
      return head;

}

void OutPutLink(struct NODE* head){
            struct NODE* move=head;
            while(move->next!=NULL){
                  printf("%d",move->next->data);
                  move=move->next;
            }

      }

插入节点

void InsertNode(struct NODE* head){
      int x,y;
      struct NODE* move = head->next;
      struct NODE* fresh = malloc(sizeof*fresh);
      printf("请输入你要在第几个节点后插入,插入什么:");
      scanf("%d%d",&x,&y);
      fresh->data=y;
      getchar();
      for(int i=1;i<x;i++){
            move=move->next;
      }
      fresh->next=move->next;
      move->next=fresh;
      return;

}

删除节点

void DeleteNode(struct NODE* head){
      int m;
      struct NODE* save;
      struct NODE* move=head;
      printf("请输入你要删除第几个结点:");
      scanf("%d",&m);
       for(int i=1;i<m;i++){
            move=move->next;
      }
      save=move->next;
      move->next=move->next->next;
      free(save);
      save=NULL;

      return;

}

判断是否空表

IsEmpty(struct NODE* head){
	return head->next==NULL;
}

查找某个元素位置

Find(struct NODE* head,int data){
	struct NODE* move = head->next;
	while(move!=NULL&&move->data!=data){
		move=move->next;
	}
	return move;
}

销毁链表

void DestoryLink(struct NODE* head){
      struct NODE* save=head;
      while(head!=NULL){
            save=head->next;
            free(head);
            head=save;
      }

      if(NULL==head){
            printf("链表已被销毁");
      }
}

循环链表

关于循环链表就是将尾结点的next不是指向NULL而是重新指向头结点或者首节点,这样整个链表就形成了一个圆环,无论从哪一个节点都可以顺利地遍历链表的每个元素,而单链表却只能从头结点才可以做到。

下面我们可以用一个经典案例体验下循环链表的妙处。那就是著名的约瑟夫问题。

约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。

上述约瑟夫环可以作为一个循环链表,将1-n分别放进一个个节点中,然后每出列一个就删除一个节点,并且打印出节点数据。

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

struct NODE{
	int data;
	struct NODE* next;

};

struct NODE* Creatlink(int n);
void DeleteNode(struct NODE* head,int man,int num);


int main(void){
      int man,n,num;
      printf("请输入环内人数:");
      while(1){
                 scanf("%d",&n);
                  getchar();
      if(n<1){
            printf("error!请从新输入");
      }else{
            break;
      }
 }
      printf("请输入从第几个人开始:");
      while(1){
                 scanf("%d",&man);
                  getchar();
      if(man<1||man>n){
            printf("error!请从新输入");
      }else{
            break;
      }
 }

       printf("请输入报数从1到几:");
            while(1){
                       scanf("%d",&num);
                        getchar();
            if(num<1){
                  printf("error!请从新输入");
            }else{
                  break;
            }
       }

      struct NODE* head =Creatlink(n);
      printf("出列顺序表:\n");
      DeleteNode(head,man,num);
		return 0;

}
struct NODE* Creatlink(int n){
      int len,i,val;
      struct NODE* head=malloc(sizeof*head);
      struct NODE* move=head;

      move->next=NULL;
      if(head==NULL){
            printf("分配内存失败");
            exit(-1);
      }

      len=n;

      for(i=1;i<=len;i++){
            struct NODE* fresh=malloc(sizeof*fresh);
            if(fresh==NULL){
                  printf("分配内存失败");
                  exit(-1);
            }

            fresh->data=i;

            move->next=fresh;
            fresh->next=NULL;
            move=fresh;

      }
      return head;

}
void DeleteNode(struct NODE* head,int man,int num){
      int m;
      struct NODE* save;
      struct NODE* move=head->next;

       for(int i=1;i<man;i++){
            move=move->next;
      }
      while(move->next!=move){
            for(int i=1;i<num-1;i++){
                  move=move->next;
      }
            save=move->next;
            printf("%d ",save->data);
            move->next=move->next->next;
            move=move->next;
            free(save);
            save=NULL;
      }
      printf("%d \n",move->data);
      free(move);
      move=NULL;
      free(head);
      head=NULL;

      return;

}

双向链表

对应单链表的就有双向链表,前者只有后继元素的地址,而后者则还有前驱元素的地址,这样虽然增加了一些内存上的开支,但是也带来了很多功能和效率上的好处。比如更加有利于搜索和查找元素,而且双向链表的增加和删除操作也更加方便,安全,不会一不小心将整个链表丢失掉。

任然使用上述循环链表中的案例,将约瑟夫环问题用双向链表实现一遍。

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

struct NODE{
	int data;
	struct NODE* next;
	struct NODE* prior;

};

struct NODE* Creatlink(int n);
void DeleteNode(struct NODE* head,int man,int num);


int main(void){
      int man,n,num;
      printf("请输入环内人数:");
      while(1){
                 scanf("%d",&n);
                  getchar();
      if(n<1){
            printf("error!请从新输入");
      }else{
            break;
      }
 }
      printf("请输入从第几个人开始:");
      while(1){
                 scanf("%d",&man);
                  getchar();
      if(man<1||man>n){
            printf("error!请从新输入");
      }else{
            break;
      }
 }

       printf("请输入报数从1到几:");
            while(1){
                       scanf("%d",&num);
                        getchar();
            if(num<1){
                  printf("error!请从新输入");
            }else{
                  break;
            }
       }

      struct NODE* head =Creatlink(n);
      printf("出列顺序表:\n");
      DeleteNode(head,man,num);
		return 0;

}
struct NODE* Creatlink(int n){
      int len,i,val;
      struct NODE* head=malloc(sizeof*head);
      struct NODE* move=head;

      move->next=NULL;
      if(head==NULL){
            printf("分配内存失败");
            exit(-1);
      }

      len=n;

      for(i=1;i<=len;i++){
            struct NODE* fresh=malloc(sizeof*fresh);
            if(fresh==NULL){
                  printf("分配内存失败");
                  exit(-1);
            }

            fresh->data=i;

            move->next=fresh;
            fresh->next=NULL;
            fresh->prior=move;
            move=fresh;

      }
      move->next=head->next;//题目要求不包含空的头结点,所以指向首节点
      head->next->prior=move;
      return head;

}
void DeleteNode(struct NODE* head,int man,int num){
      int m;
      struct NODE* save;
      struct NODE* move=head->next;

       for(int i=1;i<man;i++){
            move=move->next;
      }
      while(move->next!=move){
            for(int i=1;i<num;i++){
                  move=move->next;
      }
            save=move;
            printf("%d ",save->data);
            move->next->prior=move->prior;
            move->prior->next=move->next;
            move=move->next;
            free(save);
            save=NULL;
      }
      printf("%d \n",move->data);
      free(move);
      move=NULL;
      free(head);
      head=NULL;

      return;

}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值