链表的插入、删除、查询以及部分反转链表操作。

尾插法创建单链表

void CreatByRear(Node *head)  //尾插法创建单链表;
{
	Node *last,*pnew;
	char name[20];
	int number;
	last = head;//last指向头结点;
	printf("请输入学生的学号和姓名:\n");
	while(1)
	{
		scanf("%d",&number);
		if(number==0)
			break;
		scanf("%s",name);
		pnew=(Node *)malloc(sizeof(Node));//分配每一个新结点的内存空间;
		strcpy(pnew->name,name);
		pnew->number=number;
		last->next=pnew;//原来的结点指向新的结点,让上一个结构体中的next存放下一个结构体的首地址;
		last=pnew;//(*last).next,让last存放最后一个结构体的地址,方便下一次循环时使用这个结构体的 next; 
	}
	last->next=NULL;//链表的尾结点指针指向空,也就是结束循环后,让最后一个结构体中的 next指向空; 
}

头插法创建单链表 

void CreatByHead(Node *head)  //头插法创建单链表;
{
	Node *pnew;
	char name[20];
	int number;
	printf("请输入学生的学号和姓名:\n");
	while(1)
	{
		scanf("%d",&number);
		if(number==0)
			break;
		scanf("%s",name);
		pnew=(Node *)malloc(sizeof(Node));
		strcpy(pnew->name,name);
		pnew->number=number;
		pnew->next=head->next;
		head->next=pnew;
	}
}

单链表的插入

插入一个结点,就是让插入链表的结点的指针域内存储下一个结点的地址(或者NULL),让上一个结点的指针域内存储所插入链表的结点的地址。

在表中添加结点

设计一个函数,在单链表的第i个位置上插入新结点,如下所示。

  • 首先从链表的头结点开始,找到链表的第i-1个结点的地址p。
  • 如果该结点存在,则可以在第i-1个结点后面插入第i个结点。为插入的新结点分配内存,然后向新结点输入数据。
  • 插入时,首先将新结点的指针s指向原来第i个结点(s->next = p->next),然后将第i-1个结点指向新结点(p->next = s)

i 的大小从首元结点开始计数,首点也就是第一元素结点,它是头结点后边的第一个结点。

void Insert(Node* head,int i)
{
	Node *p=head,*s;    //定义指针p,指向head;
	int j=0;
	while(j<i-1 && p)   //j-1;
	{
		p=p->next;
		j++;
	}
	if(p)
	{
		printf("请输入待添加学生的学号和姓名:\n");
		s=(Node *)malloc(sizeof(Node));	//定义s指向新分配的空间;
		scanf("%d",&s->number);
		scanf("%s",s->name);
		s->next=p->next;			//新节点指向原来的第i个节点; 
		p->next=s; 					//新节点成为新链表的第i个节点; 
	}
}

在表首位置后添加结点

  • 首先为插入的新结点分配内存,然后向新结点输入数据。
  • 插入时,首先将新结点的指针指向链表的首元结点(s->next = head->next),然后将头节点的指针指向新结点(head->next = s)
void InsertHead(Node *head)
{
	Node *s;
	printf("请输入待添加学生的学号和姓名:\n");
	s = (Node *)malloc(sizeof(Node));		//定义s指向新分配的空间。
	scanf("%d",&s->number);
	scanf("%s",s->name);
	s->next = head->next;		//新结点的指针指向首元结点; 
	head->next = s;				//头结点的指针指向新结点; 
}

在链表最后添加结点 

  • 首先找到尾结点。
  • 插入时,为插入的新结点分配内存,再向新结点输入数据,将尾结点的指针指向要插入的新结点(p->next = s),新结点则指向空指针(s->next = NULL)
void InsertHead(Node *head)
{
	Node *p=head,*s;
	while(p && p->next)		//找到链表最后一个结点的地址; 
		p=p->next; 
	if(p)
	{
		printf("请输入学生的学号和姓名:\n");
		s = (Node *)malloc(sizeof(Node));		//定义s指向新分配的空间;
		scanf("%d",&s->number);
		scanf("%s",s->name);
		p->next = s;			//尾结点的指针指向新结点; 
		s->next = NULL;			//新结点的指针指向NULL; 
	}
}

单链表的删除 

  • 声明一个Delete函数,函数中有两个参数,其中head表示链表的头指针,pos表示要删除结点在链表中的位置。定义整形变量j来控制循环次数,然后定义指针变量 p 表示该结点之前的结点。
  • 接着用循环找到要删除结点的前一个结点 p
  • 如果该结点存在并且待删除结点存在,则将指针变量 q 指向待删除结点(q=p->next)
  • 再连接要删除结点两边的结点(p->next=q->next)
  • 并使用free函数将q指向的内存空间进行释放(free(q))
void Delete(Node *head,int pos)
{
	Node *p=head,*q;
	int j=0;
	printf("\n**********删除第%d个学生**********\n",pos);
	while(j<pos-1 && p)  //通过循环,找到第pos-1个结点的地址p;
	{
		p=p->next;
		j++; 
	}
	if(p==NULL || p->next==NULL)	//第pos个结点不存在; 
		printf("the pos is ERROR!"); 
	else
	{
		q=p->next;		//q指向第pos个结点; 
		p->next=q->next;//连接被删除结点两边的结点; 
		free(q);		//释放要删除结点的内存空间; 
	}
}

在main函数中添加代码 Delete(head,pos); //删除链表的第pos个元素。


单链表的查询

  • 声明一个search函数,函数中有两个参数,其中head表示链表的头指针,name表示要查找的值。定义指针变量p,使其从首元结点开始到链表结束。
  • 如果某结点的成员值和给定值不等,则继续查找下一个结点(p=p->next)。
  • 如果查找成功,则返回结点的地址值。
  • 如果查找失败,则打印提示信息,并返回NULL。
Node *search(Node *head,char name[])	//在单链表head中找到与name所存相同字符串的结点;
{
	Node *p=head->next;
	while(p)
	{
		if(strcmp(p->name,name)!=0)
			p=p->next;
		else
			break;	//查找成功;	
	}
	if(p==NULL)
		printf("没有找到值为%s的结点!",name);
	return p;
}

 此外,main函数中可以添加函数代码为如下所示:

void main()
{
	Node* head;  		 	//定义单链表头指针;
	Node* p;				//定义指针变量; 
	head = initlist();		//初始化单链表; 
	CreatByRear(head);		//尾插法创建单链表; 
	OutPut(head);			//输出单链表; 

	printf("\n**********请输入查找学生的姓名**********\n") ;
	char name[10000];
	scanf("%s",name);		//输入所要查找的东西; 
	p=search(head,name);	//查找"name"的结点,并将其地址赋给指针变量p;

	printf("\n**********查找到的信息如下**********\n");
	printf("学号:%d\n\n",p->number); //输出学号;
	printf("姓名:%s\n",p->name);     //输出姓名; 
}


单链表的长度

  • 单链表的长度是隐形表示的,当从首元结点开始,一次遍历链表的所有结点,并同时统计结点个数。
  • 最后返回结点个数值 。
int ListLength(LinkList head)
{
	int count=0;
	Node *p;
	p=head->next;		//指针变量p指向链表的首元结点;
	while(p)			//结点存在,表示链表没有遍历结束;
	{
		count++;
		p=p->next;		//指向当前结点的下一个结点; 
	}
	return count;
}

 main函数中需添加代码如下所示:

    int length;
	length = ListLength(head);
	printf("\n共有%d条学生信息\n",length);

不带头结点的单链表 

1.不带头结点单链表的插入

链表的插入操作如果在链表的首位置

首先为插入的新结点分配内存,然后将新结点的指针s指向原来首结点(s->next=head),最后将头指针指向新结点(head=s),这样就完成了插入结点的操作,很显然,这种情况下,头指针发生了改变,所以需要返回新的头指针。

链表的插入操作如果插入位置不是首位置,则与有头结点的链表插入操作相同。 

2.不带头结点单链表的删除 

删除的结点如果是链表的首结点

定义指针变量q指向待删除结点(q=head),再让头指针指向第二个结点(head=head->next)成为新的首结点,最后释放原来的首结点(free(q))则这样就完成了删除首结点的操作。很显然,这种情况下头指针发生了改变,所以需要返回新的头指针。

 删除的结点如果不是链表的首结点,则与有头结点的链表删除操作相同。


反转链表

迭代

有头结点

node *fanzhuan(node *head)
{
	if(head==NULL || head->next==NULL)
	{
		return head;
	}
	node *beg,*mid,*end;
	beg=NULL;
	mid=head->next;             //无头结点,mid=head;
	end=head->next->next;       //无头结点,end=head->next;
	while(1)
	{
		mid->next=beg;
        if(end==NULL)
		{
			break;
		}
		beg=mid;
		mid=end;
		end=end->next; 
	}
	head->next = mid;            //无头结点,head=mid;
	return head;
	
}

头插法

所谓头插法,是指在原有链表的基础上,依次将位于链表头部的节点摘下,然后采用从头部插入的方式生成一个新链表,则此链表即为原链表的反转版。

创造新表

无头结点

node *fanzhuan(node *head)
{
	if (head == NULL || head->next == NULL) 
	{
        return head;
    }
	node *temp=NULL;
	node *newhead=NULL;

	while(head!=NULL)
	{
		temp=head;
		head=head->next;
		temp->next=newhead;
		newhead=temp;
	}
	return newhead;
}

有头结点 

node *fanzhuan(node *head)
{
    if (head == NULL || head->next == NULL) 
	{
        return head;
    }
	node *temp=NULL;
	node *newhead=(node *)malloc(sizeof(node)); //有头结点,所有创造头结点;
    newhead->next=NULL;

	head=head->next;        //先删掉原链表的头结点,让后来可以直接取第一个结点;

	while(head!=NULL)
	{
		temp=head;            //存Temp;
		head=head->next;      //删除存过的一个结点;

		temp->next=newhead->next;//头插法,从新链表的头结点后开始连接结点;
		newhead->next=temp;
	}
	return newhead;
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值