#数据结构与算法学习笔记#PTA6:链表翻转(C/C++)

2018.3.26

输入一个乱序表,每个结点包含当前地址、值、下一地址。给定乱序表结点数N和翻转周期K,把输入的乱序表按照周期K进行翻转。注意几个测试点:1.小于周期K的尾巴不翻转,2.有不在链表上的多余输入结点,3.取最大值N=100000时运行时间不能过长。

Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elements on L. For example, given L being 1→2→3→4→5→6, if K=3, then you must output 3→2→1→6→5→4; if K=4, you must output 4→3→2→1→5→6.

Input Specification:
Each input file contains one test case. For each case, the first line contains the address of the first node, a positive N (≤10^​5) which is the total number of nodes, and a positive K (≤N) which is the length of the sublist to be reversed. The address of a node is a 5-digit nonnegative integer, and NULL is represented by -1.
Then N lines follow, each describes a node in the format:

Address  Data  Next
where Address is the position of the node, Data is an integer, and Next is the position of the next node.


Output Specification:

For each case, output the resulting ordered linked list. Each node occupies a line, and is printed in the same format as in the input.


总体思路是先对输入进行排序,再进行翻转,思路很简单,但是很难降低时间复杂度。

这道题做了几天,因为总是通不过N=100000的测试样例,显示运行超时,主要原因是排序时间过长。方案一是最先是实现方法,方案二是参考网络上的可行方案修正排序后的做法,排序算法可以说是一致的了,可是还是运行超时,考虑是用vector容器创建与删除对象过程过于复杂。

以下是利用vector实现的2个方案:

方案一:

// Reversing_Linked_List.cpp: 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;



class Element {

public:
	long address;
	int data;
	long next;
};

void Read(long& begin, long& total, vector<Element>& elements);
void Print(vector<Element>& elements);
void Reversing(long &revnum, vector<Element>& elements);

int main()
{
	long begin;
	long total;
	long revnum;
	vector<Element> elements;
	cin >> begin >> total >> revnum;

	Read(begin, total, elements);
	Reversing(revnum, elements);
	Print(elements);

	system("pause");
	return 0;
}


void Read(long& begin, long& total, vector<Element>& elements) {

	for (long i = 0; i < total; i++) {
		Element e;
		cin >> e.address >> e.data >> e.next;
		elements.push_back(e);
	}

	long tail = begin;
	for (long i = 0;i < total;i++) {
		if (tail == -1) {
			if (i != total - 1) {
				elements.erase(elements.begin() + i, elements.begin() + total);
			}
			break;
		}

		for (long j = i;j < total;j++) {
			if (elements[j].address == tail) {
				tail = elements[j].next;
				if (i != j) {
					Element t = elements[j];
					elements[j] = elements[i];
					elements[i] = t;
				}
				break;
			}
		}
	}


}

void Print(vector<Element>& elements) {
	for (long i = 0;i < elements.size();i++) {
		cout << setw(5) << setfill('0') << elements[i].address;
		cout << " " << elements[i].data << " ";
		if (elements[i].next == -1) {
			cout << elements[i].next << endl;
		}
		else {
			cout << setw(5) << setfill('0') << elements[i].next << endl;
		}
	}
}

void Reversing(long &revnum, vector<Element>& elements) {
	for (long i = 0; i < elements.size();i += revnum) {
		if (i + revnum > elements.size())break;
		long mid = i + revnum / 2;
		long tail = i + revnum - 1;
		for (long j = i;j < mid;j++) {
			Element t = elements[j];
			elements[j] = elements[tail];
			elements[tail] = t;
			tail--;
		}
	}

	for (long i = 0;i < elements.size()-1;i++) {
		elements[i].next = elements[i + 1].address;
	}
 	elements[elements.size() - 1].next = -1;
}


方案二:

// Reversing_Linked_List.cpp: 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;



class Element {

public:
	int address;
	int data;
	int next;

};

void Read(int& begin, int& total, vector<Element>& elements);
void Print(vector<Element>& elements);
void Reversing(int &revnum, vector<Element>& elements);

int main()
{
	int begin;
	int total;
	int revnum;
	vector<Element> elements;
	cin >> begin >> total >> revnum;

	Read(begin, total, elements);
	Reversing(revnum, elements);
	Print(elements);

	system("pause");
	return 0;
}


void Read(int& begin, int& total, vector<Element>& elements) {

	vector<Element> e2;
	for (int i = 0; i < total; i++) {
		Element e;
		cin >> e.address >> e.data >> e.next;
		e2.push_back(e);
	}

	//顺序插入
	int tail = begin;
	while (tail!=-1) {
		int i = 0;
		int count = 0;
		int size = e2.size();
		while(count != size){
			if (e2[i].address == tail) {
				elements.push_back(e2[i]);
				tail = e2[i].next;
				e2.erase(e2.begin() + i);
			}
			else {
				i++;
			}
			count++;
		}
	}


}

void Print(vector<Element>& elements) {
	for (long i = 0; i < elements.size(); i++) {
		//输出补零
		cout << setw(5) << setfill('0') << elements[i].address;
		cout << " " << elements[i].data << " ";
		if (elements[i].next == -1) {
			cout << elements[i].next << endl;
		}
		else {
			cout << setw(5) << setfill('0') << elements[i].next << endl;
		}
	}
}

void Reversing(int &revnum, vector<Element>& elements) {

	//翻转
	for (int i = 0; i < elements.size(); i += revnum) {
		if (i + revnum > elements.size())break;
		int mid = i + revnum / 2;
		int tail = i + revnum - 1;
		for (int j = i; j < mid; j++) {
			Element t = elements[j];
			elements[j] = elements[tail];
			elements[tail] = t;
			tail--;
		}
	}

	//依次改next值
	for (int i = 0; i < elements.size() - 1; i++) {
		elements[i].next = elements[i + 1].address;
	}
	elements[elements.size() - 1].next = -1;
}


可行方案:

参考https://www.cnblogs.com/kuotian/p/5269434.html

#include <stdio.h>
#include <stdlib.h>

typedef struct Node
{
    int address;
    int data;
    int nextAddress;
    struct Node *next;
}Node;
typedef struct Node *LinkList;

int main()
{
    //排序前 
    LinkList L1, p1, q1;            
    L1 = (LinkList)malloc(sizeof(Node));    //创建头指针 
    L1->next = NULL;
    int firstAddress;
    int N, K;//N为总结点数 K为需翻转的数 
    scanf("%d %d %d", &firstAddress, &N, &K);
    p1 = L1;
    for(int i = 0; i < N; i++) {
        q1 =  (LinkList)malloc(sizeof(Node));
        scanf("%d %d %d",&q1->address, &q1->data, &q1->nextAddress);
        p1->next = q1;
        p1 = q1;
    }
    p1->next = NULL;
    

    
    //排序后 
    LinkList L2, p2;
    L2 = (LinkList)malloc(sizeof(Node));    //创建头指针 
    L2->next = NULL;
    int count = 0;
    int findAddress = firstAddress;
    p2 = L2;
    while(findAddress != -1) {            //while(count < N) {有多余结点不在链表上没通过 
    
        q1 = L1;
        while(q1->next) {
            if(q1->next->address == findAddress) {
                p2->next = q1->next;
                q1->next = q1->next->next;
                p2 = p2->next;
                count++;
//                printf("count = %d\n",count);
                findAddress = p2->nextAddress;
//                printf("findAddress = %d\n",findAddress);
            }else {
                q1 = q1->next;
            }
        }
    }
    p2->next = NULL;
    

    //Reversing
    LinkList L3, p3, q3, tail;
    L3 = (LinkList)malloc(sizeof(Node));    //创建头指针 
    L3->next = NULL;
    //将L2以头插法插入L3
    int n = count;                //防止有多余结点影响 n=N 会影响
    int k = K;
    p3 = L3;
    p2 = L2;
    while(n >= k) {
        n -= k;
        for(int i = 0; i < k; i++) {
            p3->next = p2->next;
            p2->next = p2->next->next;
            if(i == 0)
                tail = p3->next;
            else 
                p3->next->next = q3;
            q3 = p3->next;
        }
        p3 = tail;
    }
    p3->next = L2->next;
    
    p3 = L3->next;
    while(p3->next) {
        printf("%05d %d %05d\n",p3->address, p3->data, p3->next->address);//不到五位数用0补全 
        p3 = p3->next;
    }
    printf("%05d %d -1\n",p3->address, p3->data);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_20304723/article/details/79705946