C语言 单向链表 C语言数据结构之单向链表详解分析

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

C语言 单向链表 C语言数据结构之单向链表详解分析

DDsoup   2021-11-03 我要评论
想了解C语言数据结构之单向链表详解分析的相关内容吗,DDsoup在本文为您仔细讲解C语言 单向链表的相关知识和一些Code实例,欢迎阅读和指正,我们先划重点:C语言,单向链表,C语言,数据结构,下面大家一起来学习吧。

链表的概念:链表是一种动态存储分布的数据结构,由若干个同一结构类型的结点依次串连而成。

链表分为单向链表和双向链表。

链表变量一般用指针head表示,用来存放链表首结点的地址。

每个结点由数据部分和下一个结点的地址部分组成,即每个结点都指向下一个结点。最后一个结点称为表尾,其下一个结点的地址部分的值为NULL(表示为空地址)。

特别注意:链表中的各个结点在内存中是可以不连续存放的,具体存放位置由系统分配。

例如:int *ptr ;

因此不可以用ptr++的方式来寻找下一个结点。

使用链表的优点:

不需要事先定义存储空间大小,可以实时动态分配,内存利用效率高;

可以很方便地插入新元素(结点) ,使链表保持排序状态,操作效率高。

下面用课本的例子来讲解:

/*用链表实现学生成绩信息的管理*/ 
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct stud_node{
	int num;
	char name[24];
	int score;
	struct stud_node *next;
};
struct stud_node *Create_Stu_Doc();   /*新建链表*/
struct stud_node *InsertDoc(struct stud_node *head,struct stud_node *stud);   /*插入*/
struct stud_node *DeleteDoc(struct stud_node *head,int num);       /*删除*/
void Print_Stu_Doc(struct stud_node *head);              /*遍历*/
 
int main(void)
{
	struct stud_node *head,*p;
	int choice,num,score;
	char name[20];
	int size = sizeof(struct stud_node);
	
	do{
		printf("1:Create\n 2:Insert\n 3: Delete\n 4:Print\n 0:Exit\n");
		scanf("%d",&choice);
		switch(choice){
			case 1:
			    head = Create_Stu_Doc();
			    break;
			case 2:
				printf("Input num,name and score:\n");
				scanf("%d %s %d",&num,name,&score);
				p = (struct stud_node *)malloc(size);
				p->num = num;
				strcpy(p->name,name);
				p->score = score;
				head = InsertDoc(head,p);
				break;
			case 3:
				printf("Input num:\n");
				scanf("%d",&num);
				head = DeleteDoc(head,num);
				break;
			case 4:
				Print_Stu_Doc(head);
				break;
			case 0:
				break;
		}
	}
	while(choice != 0);
	
	return 0;
 } 
/*新建链表*/
struct stud_node *Create_Stu_Doc(){
	struct stud_node *head,*p;
	int num,score;
	char name[20];
	int size = sizeof(struct stud_node);
	
	head = NULL;
	printf("Input num,name and score:\n");
	scanf("%d %s %d",&num,name,&score);
	while(num != 0){
		p=(struct stud_node *)malloc(size);
		p->num = num;
		strcpy(p->name,name);
		p->score = score;
		head = InsertDoc(head,p);    /*调用插入函数*/
		scanf("%d %s %d",&num,name,&score); 
	}
	return head;
} 
/*插入操作*/
struct stud_node *InsertDoc(struct stud_node *head,struct stud_node *stud){
	struct stud_node *ptr,*ptr1,*ptr2;
	ptr2 = head;
	ptr = stud;             /*ptr指向待插入的新的学生记录结点*/
	/*原链表为空链表时的插入*/
	if(head == NULL){
		head = ptr;
		head->next = NULL;
	}else{
		while((ptr->num > ptr2->num)&&(ptr2->next != NULL)){
			ptr1 = ptr2;
			ptr2 = ptr2->next;         /*ptr1,ptr2各往后移一个结点*/ 
		}                             
		if(ptr->num <= ptr2->num){     /*在ptr1与ptr2之间插入新结点*/ 
			if(head == ptr2){
			head=ptr;
		}
		else{
			ptr1->next = ptr;
			ptr->next = ptr2;
		}
		}
		else{                         
			ptr2->next = ptr;          /*新插入结点成为尾结点*/
			ptr->next =NULL; 
		}
	}
	return head;
} 
/*删除操作*/
struct stud_node *DeleteDoc(struct stud_node *head,int num){
	struct stud_node *ptr1,*ptr2;
	/*要被删除结点为表头结点*/ 
	while(head != NULL && head->num==num){
		ptr2=head;
		head=head->next;
		free(ptr2);
	}
	if(head==NULL){
        return NULL;	
	}         /*链表为空*/ 
	/*要被删除结点为非表头结点*/
	ptr1=head;
	ptr2=head->next;      /*从表头的下一个结点搜索所有符合删除要求的结点*/
	while(ptr2 != NULL){
		if(ptr2->num == num)/*ptr2所指结点符合删除要求*/{
			ptr1->next=ptr2->next;
			free(ptr2);
		}
		else{
			ptr1 = ptr2;         /*ptr1后移一个结点*/ 
			ptr2 = ptr1->next;        /*ptr2指向ptr1的后一个结点*/ 
		}
	} 
	return head;
} 
/*遍历操作*/
void Print_Stu_Doc(struct stud_node *head){
	struct stud_node *ptr;
	  if(head==NULL){
	  	printf("\nNo Records\n");
	  	return;
	  }
	  printf("\nThe Students'Records Are:\n");
	  printf("Num\t Name\t Score\t");
	  for(ptr=head;ptr!=NULL;ptr=ptr->next){
	  	printf("%d\t%s\t%d\n",ptr->num,ptr->name,ptr->score);
	  }
} 

申请大小为 struct stud_node 结构的动态内存空间,新申请到的空间要被强制类型转换成

struct stud_node 型的指针,并保存到指针变量p中,如下:

struct stud_node*p;

p = ( struct stud_node *)malloc(sizeof( struct stud_node ));

链表的建立:

上面程序中链表结点是按照学生学号排序的,若向根据数据输入的顺序来建立链表,如下:

/*按输入顺序建立单向链表*/
struct stud_node *Create_Stu_Doc(){
	int num,score;
	char name[20];
	int size = sizeof(struct stud_node);
	struct stud_node *head,*tail,*p;
	head=tail=NULL;
	printf("Input num,name and score:\n");
	scanf("%d %s %d",&num,name,&score);
	while(num!=0){
		p=(struct stud_node *)malloc(size);
		p->num = num;
		strcpy(p->name,name);
		p->score = score;
		p->next = NULL;
		if(head == NULL){
			head = p;
		}else{
			tail->next=p;       /*把原来链表的尾结点的next域指向该新增的结点*/
			tail=p;
		}
		scanf("%d %s %d",&num,name,&score);
	}
	return head;
} 

由于按数据输入建立链表时,新增加的结点会加在链表末尾,所以该新增结点的 next 域应置成 NULL : p->next = NULL.

链表的遍历:

为了逐个显示链表每个结点的数据,程序要不断从链表中读取结点内容,显然需要用到循环。

在for语句中将ptr的初值置为表头head,当ptr不为NULL时循环继续,否则循环结束。不可以用ptr++来寻找下一个结点。

链表的插入:

插入原则:先连后断。

首先找到正确位置,然后插入新的结点。寻找正确位置是一个循环的过程:从链表head开始,把要插入的结点stud的num分量值与链表中结点的num分量值逐一比较,直到出现要插入结点的值比第 i 结点的num分量值大,比第 i+1结点的分量值小。所以先与第 i+1 结点相连。再将 i 结点 与 i+1结点断开,并让 i 结点与 stud 结点相连。

链表的删除:

删除原则:先接后删。

若被删除结点是表头则 head=head->next ;

其他内容省略。

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们