单向链表操作中的二级指针的运用

前段时间在陈皓的博客上看到了一片关于利用二级指针删除链表的操作,讲的是利用二级指针高效的删除链表中的某个节点,当时没怎么看懂,代码太精简了。后来下来仔细的研究了一下,后来又仔细研究了<<C和指针>>书中的有关指针的介绍,还是慢慢的理解了二级指针在链表中的妙用。

现在就谈谈二级指针在链表中的应用吧,在这里主要探讨3个函数,单向链表的快速创建,插入,删除,查找操作。

1 下面是链表的创建函数:

#include<stdio.h>
#include <stdlib.h>
typedef struct node {

	int value;
	struct node * next;

}Node;

Node *head = NULL;
Node *create(int value)
{
	Node *node =(Node *)malloc(sizeof(Node));
	if (node == NULL)
		return NULL;
	node->value = value;
	node->next = head;
	head = node;
	return node;

}
多次调用此函数就可创建一条链表,此函数在我前面的一篇博客中有讲到。

2 下面是插入函数,插入函数有两个版本,2.1版本要冗长些,容易理解。2.2版本叫精简,理解要稍微难些。

代码 2.1:

/*说明:
**链表按升序插入时可能有3种情况存在:
** 1 插入在头结点的前面, 2 插入在中间任意节点 ,3 插入在最后一个节点之后
**在找到可以插入的节点的时候,都要进行的操作是:待插入的节点的next域指向当前节点,
**修改前一个节点的next域指针,使其指向待插入的节点,。如图所示:
**但当我们找到可以插入的节点时,我们已经错过了前一个节点,所以一般情况下我们会
**声明一个prev指针,来保存前一个节点的地址。这样就可以修改前一个节点的next域了,
**整个链表的遍历实际是由current这一个指针来完成,current = current->next;
**如下面的代码所示:
*/
//此函数是按升序来插入结点的,那就是说此函数既可以实现链表的创建,也可以对链表排序。
//在已知一个链表的情况下,也可以用此函数来把已知链表的结点来排序(可以自己换个函数名即可),最终
//生成一条新的有序的链表,再把以前的链表释放了,就实现了链表的排序。此种方法的排序只不过用以前链表的
//值来创建了一条新的有序链表而已。
int list_insert(Node **head,int new_value)
{

	//二级指针的使用不是目的,目的是用二级指针改变指针变量的值
	Node *previous = NULL;
	//让当前指针指向头节点
	Node *current  = *head;
	Node *new;
	while (current!=NULL&&current->value <= new_value) {
		
			
			previous = current;//保存上一级节点的地址
			current = current->next;

	}
	new = (Node *)malloc(sizeof(Node));
	if (new == NULL)
		return -1;
	
	new->value = new_value;
	new->next = current;
	if (previous == NULL) {
		*head = new;//让头指针指向new
	} else 
		previous->next = new;
	return 0;


}

代码 2.2 :

/*说明:
**优化上面的代码,改变遍历链表的方式,不在声明prev指针,因为这个指针的声明也是
**为了要访问当前节点的前一个节点的next域,然后改变next域指针使其指向待插入的节点.
**那我们何专门不声明一个指针来保存next域的地址,通过这个指针来间接改变前一个节点的next域呢?
**这样的话,访问链表的方式也发生了改变,不在是current孤军奋战了,而是用到下面两句话:
**current=*root;root = &current->next;这样的代码就显得更精简,执行效率也高,也不用考虑前面
**提到的三种情况了。
*/																		
int list_insert(Node **root,int new_value)
{

	//head既可以保存头指针的的地址,也可以保存指当前节点的前一个节点
	//的next域地址
	Node *current;
	Node *new;
	while ((current=*root)!=NULL&&current->value<=new_value) {

			root = &current->next;
		
	}
	new = (Node *)malloc(sizeof(Node));
	if (new == NULL)
		return -1;
	
	new->value = new_value;
	/*在链表中插入新节点*/
	new->next = current;
	*root = new;//改变头指针
	return 0;

}
3 下面是删除函数:

代码 3:

/*说明:
**链表的遍历的关键代码就是:current=*root;root =&current->next;
**通过一个二级指针来保存节点的next域的地址,这样就不用再声明一个prev指针
**来单独保存当前节点的前一个节点的地址了。
*/
int list_delate(Node **root,int new_value)
{

	Node *current;
	Node *old;
	current = *root;
	//current要移动,必须要有个变量保存当前节点的next
	//然后才有机会重新给current赋值
	while((current=*root)!=NULL&&current->value!=new_value) {
		
		root =&current->next;//头指针没有改变,指针头指针的指针改变了
	}
	if(current ==NULL) {
	
		printf("waring: the new_value: %d is not exist in the list!\n",new_value);
	} else {
		
		old = current;
		*root = current->next;
		free(old);
	}
	
	return 0;
}
4 下面是查找函数:

代码 4 :

Node *list_search(Node **root,int new_value)
{
	Node *current;
	current = *root;
	while ((current = *root)!=NULL) {
		if (current->value==new_value) {
		
			break;
		} else {
			root = &current->next;//root最开始保存头指针的地址,然后始终保存当前节点的next域地址。
		}
	}
	return current;
	
}
5 下面是测试代码:

代码 5:

int main(int argc,char **argv)
{

	int i= 0;
	Node *head = create(1);
	list_insert(&head,3);
	list_insert(&head,25);
	list_insert(&head,16);
	list_insert(&head,100);
	
	Node *cur = list_search(&head,16);
	printf("cur->value = %d\n",cur->value);
	list_insert(&head,3);
	list_delate(&head,16);
	#if 0
	list_delate(&head,16);
	printf("head3 =%p\n",head);

	list_delate(&head,22);
	printf("head3 =%p\n",head);

	list_delate(&head,10);
	printf("head3 =%p\n",head);
	
	
	#endif
	//两个指针同时在移动 
	//一个是指向当前节点的指针 
	//另一个是指向当前节点的next域的指针
	Node **p=&head;
	Node *current;
	while ((current=*p)!=NULL) {
		
			printf("current->value = %d\n",current->value);
			p = &current->next;
			
			
	}
	#if 0
	for (i = 0;i<3;i++) {

		printf("head->value = %d\n",head->value);
		head = head->next;

	}
	#endif
	return 0;
}
6  欢迎留言讨论,本文原创,转载请注明原出处。原地址链接: http://http://blog.csdn.net/pengqian652/article/details/12999263




  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值