• 单链表的插入删除以及逆转


    一、背景说明

    参加了某团购网站2014年的校招笔试,里面考到了一道单链表反转的题目。要求每隔k个元素反转一次。

    如k=1时,链表1,2,3,4,5,6,7,8反转后为1,2,3,4,5,6,7,8

        k=3时,链表1,2,3,4,5,6,7,8反转后为3,2,1,6,5,4,8,7

    当时不会做,于是回来重新复习了下链表并实现了以下操作:

    1)创建头结点

         注意这里要把头结点L返回,因为传入的形参是头结点指针,给头结点分配空间后指针地址变化了。所以需要返回指针L才行。

         (这里改变的不是指针指向的内容,而是指针的地址)

    2)在位置i插入元素

         找到要插入的位置i的前一个元素p。

         创建一个新的结点s,s的后缀指针指向p的下一个。

         p的后缀指针指向s。

    3)删除位置i的元素

          找到要删除的位置i的前一个元素p。

         r为p的下一个元素,即要删除的元素。

         p的后缀指针指向r的下一个元素。

         释放r。

    4)单链表反转

        提示:假设有三个元素pPrev,pNode,pNext。要想反转pNode,pPrev,则把pNode的下一个指向pPrev就可以了。

                    但是此时链表就断开了,所以还需要记录下pNext的位置。不断循环直到链表尾(pNode为空)即可。

    5)单链表每隔K个反转

        提示:计算链表长度,除以反转间隔k得出要反转的趟数。参照4的方法反转即可。


    二、代码实现

    #include <stdio.h>
    #include <stdlib.h>
    
    /*
    定义一个结构体
    */
    typedef struct Node{
    	int data;
    	struct Node *next;
    }Node,*ListNode;
    
    /*
    创建一个头结点
    */
    Node* initial(Node *L){
    	L=(Node *)malloc(sizeof(Node));
    	L->next=NULL;
     	return L;
    }
    
    
    /*
    在位置i插入一个元素x
    初始化列表是i可置1,即采用头插法添加元素。
    */
    int Insert(Node* head,int x,int i){
    	ListNode p;
    	p=head;
    	int j=1;
    	while(p->next&&j<i){//找第i-1个元素p
    		p=p->next;
    		j++;
    	}
    	if(p==NULL || j>i){
    		printf("insert error");
    		return -1;
    	}
    	Node* s=(Node *)malloc(sizeof(Node));
    	s->data = x;
    	s->next = p->next;
    	p->next = s;
    	return 0;
    }
    
    /*
    删除第i个元素
    */
    int Delete(ListNode head,int i){
    	Node *p,*r;
    	p=head;
    	int j=1;
    	
    	while(p->next&&j<i){//找第i-1个元素p
    		p=p->next;
    		++j;
    	}
    	if(p==NULL || p->next==NULL || j>i){
    		printf("delete error");
    		return -1;
    	}
    	r=p->next;
    	p->next = r->next;
    	free(r);
    	return 0;
    }
    
    /*
    单链表反转
    */
    int Reverse(Node *head){
    	Node* revHead = NULL;
    	Node* pNode = head->next;//初始为第一个元素
    	Node* pPrev = NULL;//当前元素的前缀元素指针
    	Node* pNext = NULL;//当前元素的后缀元素指针
    	while(pNode!=NULL){
    		pNext = pNode->next;//保存当前元素的后缀元素
    		if(pNext==NULL)
    			revHead=pNode;
    		pNode->next=pPrev;//当前元素的下一个指向前缀元素
    		pPrev=pNode;//前缀元素指向当前元素
    		pNode=pNext;//当前元素指向下一个要逆转的元素,即后缀元素
    	}
    	head->next = revHead;
    	return 0;
    }
    	 
    /*
    单链表每隔K个元素反转
    如k=3时1,2,3,4,5,6,7,8则反转为3,2,1,6,5,4,8,7
    */
    
    int NumReverse(Node *head,int k){
    	Node* lastTail = head; //上一组列表的表尾
    	Node* pNode = head->next; //当前元素
    	Node* groupTail = NULL; //当前组的表尾
    	Node* pPrev = NULL;//当前元素的前缀元素
    	Node* pNext = NULL;//当前元素的后缀元素
    	int count =0; //已反转的趟数
    	int length =0;//要反转的趟数
    
    	while(pNode!=NULL){//计算链表长度
    		length++;
    		pNode = pNode->next;
    	}
    	
     	pNode = head->next;
    	length=length/k;//要逆转的趟数
    	
    	while(pNode!=NULL && count<=length){//逆转length躺
    		pPrev = NULL;
    		pNext = NULL;
    		groupTail = pNode;
    		 
    		int i=0;
    
    		while(pNode!=NULL && i<k){//如果下一个元素还有且当前趟已逆转个数i<k则继续反转
    			pNext = pNode->next;
    			pNode->next=pPrev;
    			pPrev=pNode;
    			pNode=pNext;
    			i++;
    		}
    
    		lastTail->next = pPrev; //上一组的链表表尾指向当前趟的第一个元素
    		lastTail = groupTail;  //修改上一组的链表表尾为当前组的链表表尾
    		groupTail->next = pNode; //当前组的链表表尾元素的后缀指针指向下一组的开始元素
    		count++;
    		
    	}
    	
    	
    	return 0;
    }
    
    /*
    打印链表
    */
    void Print(Node* head){
    	Node* p;
    	p=head;
    	while(p->next){
    		p=p->next;
    		printf("%d ",p->data);
    	}
    	printf("
    ");
    }
    
    int main(){
    	Node* head;
    	head=initial(head);
    
    	printf("初始化的链表:
    ");
    	for(int i=1;i<=20;i++){
    		Insert(head,i,1);
    	}
    	Print(head);
    
    	printf("反转后的链表:
    ");
    	Reverse(head);
    	Print(head);
    
    	printf("按间隔k=4反转后的链表:
    ");
    	NumReverse(head,4);
    	Print(head);
    
    	printf("删除第2-11的元素后的链表:
    ");
    	for(int i=1;i<=10;i++){
    		Delete(head,2);
    	};
    	Print(head);
    	return 0;
    }

    三、运行结果

    注:代码在Ubuntu下用GCC/G++编译运行均通过



  • 相关阅读:
    DRF小结
    js中BOM与DOM的概念与区别
    css单位分析、颜色设置与调色板
    css中伪类与伪元素的区别
    flexbox与grid layout的区别
    grid的简单使用
    position属性的总结
    html,css
    homework
    aboutme and my goal
  • 原文地址:https://www.cnblogs.com/pangblog/p/3320199.html
Copyright © 2020-2023  润新知