zoukankan      html  css  js  c++  java
  • 又见链表 --- 另一种Creat方式与反转

    链表

    作为一种数据结构,链表以其方便的增删查改功能,实现了无数经典有用的程序。
    在之前的帖子里,我构建链表的方式是建立一个不储存数据的head节点,然后通过一边输入数据一边建立结点的方式构建整个链表。
    与之前不同的是,这里建立的是包含数据的头结点head:

    下面是代码,包含创建部分,输出部分,删除部分,和插入部分。

    struct Node
    {
    	int data;
    	Node *next;
    };
    
    int n = 0; // 结点数 
    
    //=============Node_Creat==============//
    Node *Node_Creat()
    {
    	Node *head = NULL; // 头指针置NULL 
    	
    	Node *p1,*p2; // 开辟一个Node大小的空间 使p1和p2指向该空间 
    	p1 = p2 = (Node *)malloc(sizeof(Node));
    	if(p1 == NULL || p2 == NULL)
    	{
    		printf("Overflow
    ");
    		exit(1);
    	}
    	
    	scanf("%d",&p1 -> data); 
    	
    	while(p1 -> data >= 0)
    	{
    		n++;
    		
    		if(head == NULL)
    		{
    			head = p1;
    		} 
    		else
    		{
    			p2 -> next = p1;
    		}
    		
    		p2 = p1;
    		p1 = (Node *)malloc(sizeof(Node));
    		if(p1 == NULL)
    		{
    			printf("Overflow
    ");
    			exit(1);
    		}
    		
    		scanf("%d",&p1 -> data);
    	}
    	
    	p1 = NULL;
    	p2 -> next = NULL;
    	return head;
    }
    
    //============Node_Print==============//
    void Node_Print(Node *head)
    {
    	Node *p = head;
    	if(head == NULL) // 链表为空 
    	{
    		printf("Empty!
    ");
    		return ;
    	}
    	else
    	{
    		printf("Total: %d Node
    ",n);
    		while(p != NULL)
    		{
    			printf("%d ",p -> data);
    			p = p -> next; 
    		}
    		printf("
    ");
    	}
    }
    
    //==============Node_Delete()===============//
    void Node_Delete(Node *head,int num)
    {
    	Node *p1,*p2;
    	p1 = head;
    	
    	if(p1 == NULL) // 链表为空
    	{
    		printf("Empty
    ");
    		return ;
    	} 
    	
    	if(num > n) // 结点不存在 
    	{
    		printf("Not Found!
    ");
    		return ;
    	}
    	
    	n--; // 结点数-1 
    	
    	int i;
    	for(i = 1; i < num; i++)
    	{
    		if(p1 -> next == NULL)break;
    		
    		p2 = p1;
    		p1 = p1 -> next;
    	}
    	
    	if(p1 == head) // 头节点 即第一个
    	{
    		head = p1 -> next;
    	}
    	else
    	{
    		p2 -> next = p1 -> next;
    		free(p1);
    	}
    	
    	Node_Print(head);
    }
    
    //============Node_Insert()============//
    void Node_Insert(Node* head,int num,int i_data)
    {
    	Node * newNode;
    	newNode = (Node *)malloc(sizeof(Node));
    	if(newNode == NULL)
    	{
    		printf("Overflow
    ");
    		exit(1);
    	}
    	newNode -> data = i_data;
    	newNode -> next = NULL;
    	
    	Node *p1,*p2;
    	p1 = head;
    	
    	for(int i = 1 ;i < num; i++)
    	{
    		p2 = p1;
    		p1 = p1 -> next;
    	}
    	
    	p2 -> next = newNode;
    	newNode -> next = p1;
    	
    	n++; // 结点数+1 
    	
    	Node_Print(head);
    }
    
    

    样例:

    链表的反转

    我这里采用的方法是 改变两个结点间next指针的指向,原结点next指针指向下一个结点,反转后指向前一个结点。

    Node* Node_Reverse(Node* head)
    {
        Node* pNow = head;//当前结点
        Node* pPrv = NULL;//当前结点的前一个结点
        Node* pReversedHead = NULL;//反转链表头结点
        
        Node* pNext = NULL;//当前结点的下一个结点
        while(pNow != NULL)
        {
            pNext = pNow -> next;
            if(pNext == NULL)//如果当前结点的下一个结点为空,那么反转链表的头结点就是当前结点。
            pReversedHead = pNow;
    
            pNow -> next = pPrv;//当前结点指向前一个结点
    
            pPrv = pNow;//pPrv和pNow往前移动。
            pNow = pNext;//这里要使用前面保存下来的pNext,不能使用pNow->next
        }
        return pReversedHead;//返回反转链表头指针。
    }
    

    大概的一个流程图(反转第一个结点)

    注:红色箭头代表pPrev,pNext和pNow的移动,蓝色代表next指针的指向。

  • 相关阅读:
    Halcon图像分割
    Halcon图像变量
    C# 线程同步
    C# 单例模式实现
    C# 限制窗体弹窗显示必须关闭后才能重新实例化窗体
    Java定时清理过期文件
    GrayLog + Logspout + Docker 实现分布式日志聚合
    基于Spring Security OAuth2搭建的Spring Cloud 认证中心
    快速搭建Docker Registry私有仓库
    让你的Spring Boot应用快速运行在Docker上面
  • 原文地址:https://www.cnblogs.com/qq952693358/p/5503244.html
Copyright © 2011-2022 走看看