数据结构-双向链表


    双向链表 
        一个数据节点 保存的数据 
                    保存逻辑上的下一个(后继节点)
                    也保存逻辑上的上一个(前驱节点)

        不带头结点的双向链表
        带头结点的双向链表 

    代码实现:  "带头结点的双向链表"

        //数据元素的类型 
        typedef int ElemType;       //数据元素中数据的类型
        typedef struct node 
        {
            ElemType data;          //数据域 --> 存储数据 
            struct node * next;     //指针域 --> 保存逻辑上的下一个
            struct node * prev;                 //保存逻辑上的上一个
        } DNode;

        //头结点的类型 
        typedef struct List 
        {
            struct node * first;      //指向链表的第一个节点
            struct node * last;       //指向链表的最后一个节点
            int num;            //记录链表中元素的个数 
            //...
        } DList;

    基本操作:  增删改查 


        练习: 
            1)根据用户输入的数据的顺序, 创建一个带头结点的双向链表
                将新链表返回,  然后再打印输出 

                BothwayLinkedListWithHead.c   /   BothwayLinkedListWithHead.h  

                    

DList * create_bothway_list()
{
    //1.创建一个头结点, 并初始化
	DList * list = (DList *)malloc( sizeof(DList) );
	list->first = NULL;
	list->last = NULL;
	list->num = 0;

    ElemType d;
    while(1)
    {
	    //2.获取数据 
		scanf("%d", &d );
		if( d == 0 )
		{
			break;
		}
	    
	    //3.创建数据节点,并初始化 
		DNode * pnew = (DNode*)malloc( sizeof(DNode) );
		pnew->data = d;
		pnew->next = NULL;
		pnew->prev = NULL;
	    
	    //4.把新节点 加入到链表中 
		if( list->first == NULL )	//从无到有 
		{
			list->first = pnew;
			list->last = pnew;
		}
		else	//从少到多 
		{
			//尾插法 
			list->last->next = pnew;
			pnew->prev = list->last;
			list->last = pnew;

			//头插法
			//pnew->next = list->first;
			//list->first->prev = pnew;
			//list->first = pnew;
			
		}
		list->num ++;	//元素个数 +1 
	}
	
    //5.将新链表返回 
    return list;
}

           

//打印链表
void print_list( DList * list )
{
	if( list == NULL )	//链表不存在 
	{
		printf("list is NULL \n");
		return ;
	}

	//正向
	DNode * p = list->first;	//遍历指针   
	while( p )
	{
		printf("%d ", p->data );
		p = p->next;
	}
	putchar('\n');

	//倒序
	p = list->last;
	while( p )
	{
		printf("%d ", p->data );
		p = p->prev;
	}
	putchar('\n');

	printf("num = %d\n\n", list->num );
	
}

        

                main.c  
                    #include "BothwayLinkedListWithHead.h"

                    int main()
                    {                          

                   

                    }


            2)根据用户输入的数据的顺序, 逆序创建一个带头结点的双向链表
                将新链表返回,  然后再打印输出 

                    //头插法 

            3)根据用户输入的数据, 创建一个有序的带头结点的双向链表 (升序), 将新链表返回

                /*
                    分情况讨论:
                        比第一个还要小, 头插法
                        比最后一个还要大, 尾插法
                        中间插入, 找到第一个比它大的数的前面进行插入

                            注意: 中间插入时, 先赋值pnew的成员, 再去修复前后的关系 
                                                ☆☆☆
                */

DList * create_sort_bothway_list()
{
	//1.创建一个头结点, 并初始化
	DList * list = (DList *)malloc( sizeof(DList) );
	list->first = NULL;
	list->last = NULL;
	list->num = 0;

    ElemType d;
    while(1)
    {
	    //2.获取数据 
		scanf("%d", &d );
		if( d == 0 )
		{
			break;
		}
	    
	    //3.创建数据节点,并初始化 
		DNode * pnew = (DNode*)malloc( sizeof(DNode) );
		pnew->data = d;
		pnew->next = NULL;
		pnew->prev = NULL;
	    
	    //4.把新节点 加入到链表中
	    if( list->first == NULL )	//从无到有
	    {
			list->first = pnew;
			list->last = pnew;
	    }
	    else	//从少到多 
	    {
	    	/*
				分情况讨论:
					比第一个还要小, 头插法
					比最后一个还要大, 尾插法
					中间插入, 找到第一个比它大的数的前面进行插入
	    	*/
			DNode * p = list->first;		//遍历指针 
			while( p )
			{
				if( p->data > pnew->data )
				{
					break; 	//找到了
				}
				p = p->next;
			}

			if( p == NULL )	//没找到 
			{
				//尾插法
				list->last->next = pnew;
				pnew->prev = list->last;
				list->last = pnew;
			}
			else	//找到了 
			{
				if( p == list->first )	
				{
					//头插法

					pnew->next = list->first;
					list->first->prev = pnew;
					list->first = pnew;
				}
				else 
				{
					//中间插入
					//注意: 先赋值pnew的成员, 再去修复前后的关系
					pnew->next = p;
					pnew->prev = p->prev;
					p->prev->next = pnew;
					p->prev = pnew;
				}
			}
	    }
		list->num ++;	//元素个数 +1
	    
	}

	//5.将新链表返回
	return list;
}

            4)在双向链表中找到值为x的节点, 将其全部删除 
                如果没有找到 就不删除, 将新链表返回 

                    注意: 删除中间节点时, 先去修复前后的关系, 再去断开自身的连接  
                                                ☆☆☆

DList * delete_all_x_node( DList * list, ElemType x )
{
	if( list == NULL )	//链表不存在 
	{
		printf("list is NULL \n");
		return NULL;
	}

	//1.找到值为x的节点
	DNode * p = list->first;	//遍历指针 

	while( p )
	{
		if( p->data == x )
		{
			//找到了,就删除(分情况讨论)
			list->num --;	//元素个数 -1 

			if( p == list->first )	//删除第一个节点 (要考虑只剩下一个节点的情况)
			{
				list->first = list->first->next;
				if( list->first != NULL )	// list->num != 0 
				{
					list->first->prev = NULL;
				}
				p->next = NULL;

				free( p );

				p = list->first;	//p从下一个开始再去找

				//当唯一的一个节点也删除了  	
				if( list->first == NULL )	// list->num == 0
				{
					list->last = NULL;
				}
			}
			else if( p == list->last )	//删除最后一个节点
			{
				list->last = list->last->prev;
				if( list->last != NULL )
				{
					list->last->next = NULL;
				}
				p->prev = NULL;

				free( p );
				
				p = NULL;	//已经删到末尾了,就不需要继续了
			}
			else 	//删除中间的节点
			{
				DNode * temp = p->next;

				//先去修复前后的关系, 再去断开自身的连接  
				p->prev->next = p->next;
				p->next->prev = p->prev;
				p->next = NULL;
				p->prev = NULL;

				free( p );

				p = temp;	//继续往下找
			}
			
		}
		else 
		{
			//没找到. 就继续往下找 
			p = p->next;
		}
	}

	//将新链表返回
	return list;
}

         

             5)在双向链表中找到值为x的节点, 将所有值为x的节点的值 修改成a 
                没有找到就不修改, 将新链表返回 

DList * update_node( DList * list, ElemType x , ElemType a )
{
	if( list == NULL )	//链表不存在 
	{
		printf("list is NULL \n");
		return NULL;
	}

	DNode * p = list->first;		//遍历指针 
	while( p )
	{
		if( p->data == x )	//找到了
		{
			p->data = a;
		}
		p = p->next;
	}

	return list;
}

            6)销毁一条双向链表
                    先释放每一个数据节点 
                    再去释放头结点

void destroy_list( DList * list )
{
	if( list == NULL )	//链表不存在 
	{
		printf("list is NULL \n");
		return ;
	}

	DNode * p = list->first;	//遍历指针 

	//先释放每一个数据节点 
	while( p )
	{
		list->first = list->first->next;
		if( list->first != NULL )
		{
			//如果是删除最后一个节点时, first再往下走就已经为NULL了,
			//再去访问这个prev就会产生"段错误"
			list->first->prev = NULL;
		}
		p->next = NULL;

		free(p);

		p = list->first;
	}

    //再去释放头结点
    list->first = NULL;
    list->last = NULL;
    list->num = 0;
    free( list );
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值