1. 程式人生 > >連結串列面試題C++

連結串列面試題C++

注意頭結點的處理,如果倒敘記得將新的尾節點指向空。

示例一

給定一個整數num,如何在節點值有序的連結串列中插入一個節點值為num的節點,並且保證這個單鏈表依然有序。

#include<iostream>
#include<thread>
using std::endl;
using std::cout;

template<typename T> struct Node{
	T data;
	Node<T> *next;
};

template<typename T> class listStruct {
public:
	listStruct() = default;
	listStruct(Node<T> *h) : head(h) {}
	~listStruct() {
		Node<T> *temNext;
		while (head){
			temNext = head;
			head = head->next;
			delete temNext;
		}
	}
	void buildList(const int *sortArray, const int &length);
	void displayList();
	void addNode(const int &data);
private:
	Node<T> *head;
};
template<typename T> void listStruct<T>::addNode(const int &data) {
	Node<T> *newNode = new Node<T>;
	newNode->data = data;
	newNode->next = NULL;
	if (head == NULL) {
		head = newNode;
	}
	if (head->data > data) {
		newNode->next = head;
		head = newNode;
		return;
	}
	Node<T> *tem = head;
	Node<T> *last = NULL;
	while (tem) {
		if (tem->data > data){
			newNode->next = tem;
			last->next = newNode;
			return;
		}
		last = tem;
		tem = tem->next;
	}
	last->next = newNode;
}
template<typename T> void listStruct<T>::displayList() {
	Node<T> *tem = head;
	cout << "start:" << endl;
	while (tem){
		cout << tem->data << endl;
		tem = tem->next;
	}
	cout << "end!" << endl;
}
template<typename T> void listStruct<T>::buildList(const int *sortArray, const int &length) {
	if (length < 0) {
		return;
	}
	head = new Node<T>;
	head->data = sortArray[0];
	Node<T> *current = head;
	for (int i = 1; i < length; ++i) {
		Node<T> *tem = new Node<T>;
		tem->data = sortArray[i];
		tem->next = NULL;
		current->next = tem;
		current = tem;
	}
}



int main() {
	int sortArray[9] = { 0,1,2,4,5,6,7,8,9 };
	listStruct<int> sortList;
	sortList.buildList(sortArray, 9);
	sortList.addNode(-1);
	sortList.addNode(10);
	sortList.displayList();
	while (1){
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}


	return 0;
}

示例二

給定一個連結串列的頭結點head,再給定一個數num,請把連結串列調整成節點值都小於num的節點都放在連結串列的左邊,值等於num的節點都放在連結串列的中間,值大於num的節點,都放在剪標的右邊。
分析:將原連結串列分為三個連結串列,大於num,等於num,小於num。然後再將三個連結串列串起來。

#include<iostream>
#include<thread>
using std::endl;
using std::cout;

template<typename T> struct Node{
	T data;
	Node<T> *next;
};

template<typename T> class listStruct {
public:
	listStruct() = default;
	listStruct(Node<T> *h) : head(h) {}
	~listStruct() {
		Node<T> *temNext;
		while (head){
			temNext = head;
			head = head->next;
			delete temNext;
		}
	}
	void buildList(const int *sortArray, const int &length);
	void displayList();
	void addNode(const int &data);
	void sortList(const int &data);
	void outputNode(Node<T> *node);
private:
	Node<T> *head;
};
template<typename T> void listStruct<T>::outputNode(Node<T> *node) {
	cout << "open" << endl;
	while (node){
		cout << node->data << endl;
		node = node->next;
	}
	cout << "close" << endl;
}
template<typename T> void listStruct<T>::sortList(const int &data) {
	Node<T> *temLess = new Node<T>;
	Node<T> *temGreater = new Node<T>;
	Node<T> *temEqual = new Node<T>;
	Node<T> *lessList = temLess;
	Node<T> *greaterList = temGreater;
	Node<T> *equalList = temEqual;

	Node<T> *tem = head;
	while (tem){
		if (tem->data < data) {
			lessList->next = tem;
			lessList = lessList->next;
			tem = tem->next;
		}
		else if (tem->data == data) {
			equalList->next = tem;
			equalList = equalList->next;
			tem = tem->next;
		}
		else {
			greaterList->next = tem;
			greaterList = greaterList->next;
			tem = tem->next;
		}
	}
	lessList->next = NULL;
	greaterList->next = NULL;
	equalList->next = NULL;

	if (temLess->next) {
		head = temLess->next;
		tem = head;
		while (tem->next){
			tem = tem->next;
		}
	}
	if (temEqual->next) {
		tem->next = temEqual->next;
		while (tem->next){
			tem = tem->next;
		}
	}
	if (temGreater->next) {
		tem->next = temGreater->next;
	}
	delete temLess;
	delete temGreater;
	delete temEqual;
	
}
template<typename T> void listStruct<T>::addNode(const int &data) {
	Node<T> *newNode = new Node<T>;
	newNode->data = data;
	newNode->next = NULL;
	if (head == NULL) {
		head = newNode;
	}
	if (head->data > data) {
		newNode->next = head;
		head = newNode;
		return;
	}
	Node<T> *tem = head;
	Node<T> *last = NULL;
	while (tem) {
		if (tem->data > data){
			newNode->next = tem;
			last->next = newNode;
			return;
		}
		last = tem;
		tem = tem->next;
	}
	last->next = newNode;
}
template<typename T> void listStruct<T>::displayList() {
	Node<T> *tem = head;
	cout << "start:" << endl;
	while (tem){
		cout << tem->data << endl;
		tem = tem->next;
	}
	cout << "end!" << endl;
}
template<typename T> void listStruct<T>::buildList(const int *sortArray, const int &length) {
	if (length < 0) {
		return;
	}
	head = new Node<T>;
	head->data = sortArray[0];
	Node<T> *current = head;
	for (int i = 1; i < length; ++i) {
		Node<T> *tem = new Node<T>;
		tem->data = sortArray[i];
		tem->next = NULL;
		current->next = tem;
		current = tem;
	}
}



int main() {
	int sortArray[9] = { 9,1,2,6,5,7,4,8,0 };
	listStruct<int> sortList;
	sortList.buildList(sortArray, 9);
	sortList.sortList(5);
	sortList.displayList();
	while (1){
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}


	return 0;
}

示例三

給定兩個有序連結串列的頭結點,列印公共部分。

template<typename T> void printSameElement(Node<T> *head1, Node<T> *head2) {
	if (!head1 || !head2){
		return;
	}
	cout << "in" << endl;
	while (head1&&head2){
		if (head1->data == head2->data) {
			cout << head1->data << endl;
			head1 = head1->next;
			head2 = head2->next;
		}
		else if (head1->data > head2->data) {
			head2 = head2->next;
		}
		else {
			head1 = head1->next;
		}
	}
}

示例四

給定一個單鏈表的頭結點head,實現一個調整單鏈表的函式,使得每K個節點之間逆序,如果最後不夠k個節點一組,則不調整最後幾個節點。

template<typename T> Node<T> *reverseK(Node<T> *head,const int &k) {
	if (!head) {
		return head;
	}
	int i = 0;
	Node<T> *tem = head;
	Node<T> *start = head;
	Node<T> *end = head;
	bool firstFlag = true;
	while (tem) {
		++i;
		if (i == 1) {
			start = end;
		}
		if (i == k) {
			i = 0;
			end = tem;
			if (firstFlag) {

				Node<T> *temFront = head;
				Node<T> *temEnd;
				head = head->next;
				temFront->next = end->next;
				while (head != end) {
					temEnd = head->next;
					head->next = temFront;
					temFront = head;
					head = temEnd;
				}
				temEnd = head->next;
				head->next = temFront;
				firstFlag = false;
				tem = start;
				end = tem;
			}
			else {
				Node<T> *temFront = start->next;
				Node<T> *temEnd;
				Node<T> *temCurrent = temFront->next;
				tem = temFront;
				if (end->next) {
					temFront->next = end->next;
				}
				else {
					temFront->next = NULL;
				}
				while (temCurrent != end) {
					temEnd = temCurrent->next;
					temCurrent->next = temFront;
					temFront = temCurrent;
					temCurrent = temEnd;
				}
				temCurrent->next = temFront;
				start->next = temCurrent;
				end = tem;
			}
		}
		tem = tem->next;
	}
	return head;
}

示例五

給定一個單鏈表的頭節點head,連結串列中每個節點儲存一個整數,再給定一個值val,把所有等於val的節點刪掉。
分析:重新構建一個連結串列,不等於val就接到新連結串列後,如果等於就拋棄。注意邊界條件。

template<typename T> Node<T> *eliminateValue(Node<T> *head, const T &value) {
	Node<T> *newHead = NULL;
	Node<T> *temNode = new Node<T>;
	temNode->next = NULL;
	newHead = temNode;
	while (head) {
		if (head->data != value) {
			newHead->next = head;
			newHead = newHead->next;
		}
		head = head->next;
	}
	if (temNode->next) {
		newHead = temNode->next;
	}
	else {
		newHead = NULL;
	}
	delete temNode;
	return newHead;
}

示例六

判斷一個連結串列是否為迴文結構。
分析:
方法一:空間複雜度為 O ( N ) O(N) 。採用一個棧儲存前半段的資料,然後跟後半段的資料依次對比。
採用一個慢指標一次走一步與一個快指標一次走兩步的方法可以確定連結串列中點位置。

template<typename T> bool plalindrome(Node<T> *head) {
	std::stack<T> temStack;
	if ((!head) || (!head->next)) {
		return false;
	}
	Node<T> *fast = head;
	Node<T> *slow = head;
	bool middleFlag = false;
	while (slow){
		if (!middleFlag) {
			if (!fast) {
				middleFlag = true;
				continue;
			}
			if (!fast->next) {
				middleFlag = true;
				slow = slow->next;
				continue;
			}
			fast = fast->next;
			fast = fast->next;
			temStack.push(slow->data);
			//cout << "stack push: " << temStack.top() << endl;
			slow = slow->next;
		}
		else {
			//cout << "slow data: " << slow->data << endl;
			if (slow->data != temStack.top()) {
				return false;
			}
			else{
				//cout << "stack pop: " << temStack.top() << endl;
				temStack.pop();
				slow = slow->next;
			}
		}
	}
	return true;
}

方法二:空間複雜度為 O ( 1 ) O(1) 。將後半部分倒敘指向,然後從兩端開始遍歷是非相等。最後要恢復連結串列原序。

template<typename T> bool plalindromeNoSpace(Node<T> *head) {
	std::stack<T> temStack;
	if ((!head) || (!head->next)) {
		return false;
	}
	Node<T> *fast = head;
	Node<T> *slow = head;
	Node<T> *middleNode = head;
	Node<T> *endNode;
	bool middleFlag = false;
	bool evenFlag = false;
	while (slow) {
		if (!middleFlag) {
			if (!fast) { //偶
				middleFlag = true;
				middleNode = slow;
				evenFlag = true;
				break;
			}
			if (!fast->next) {  //奇
				middleFlag = true;
				slow = slow->next;
				middleNode = slow;
				evenFlag = false;
				break;
			}
			fast = fast->next;
			fast = fast->next;
			if (!fast) {
				middleFlag = true;
				middleNode = slow;
				evenFlag = true;
				break;
			}
			if (!fast->next) {
				middleFlag = true;
				slow = slow->next;
				middleNode = slow;
				evenFlag = false;
				break;
			}
			slow = slow->next;
		}
	}

	slow = middleNode;
	Node<T> *newEnd = slow;
	Node<T> *newHead;
	slow = slow->next;
	while (slow->next) {
		newHead = slow->next;
		slow->next = newEnd;
		newEnd = slow;
		slow = newHead;
		newHead = slow->next;
	}
	bool result = true;

	endNode = slow;
	slow->next = newEnd;
	middleNode->next = NULL;
	listStruct<T>::outputNode(head);
	listStruct<T>::outputNode(endNode);
	Node<T> *left = head;
	Node<T> *right = endNode;

	while (right!=middleNode){
		if (right->data != left->data){
			result = false;
		}
		right = right->next;
		left = left->next;
	}


	Node<T> *temCurrent = endNode->next;
	newEnd = endNode;
	while (temCurrent != middleNode) {
		newHead = temCurrent->next;
		temCurrent->next = newEnd;
		newEnd = temCurrent;
		temCurrent = newHead;
	}
	middleNode->next = newEnd;
	endNode->next = NULL;
	listStruct<T>::outputNode(newEnd);
	return result;
}

示例七

如何判斷一個連結串列是否有環,如果有環的話返回進入環的第一個節點,無環的話返回空,如果連結串列的長度為N,請做到時間複雜度為 O ( N ) O(N) ,空間複雜度為 O ( 1 ) O(1) .
分析:使用快慢指標,慢指標一次走一步,快指標一次走兩步。如果相遇則為有環,如果快指標指向NULL則無環。若有環,讓快指標從頭結點開始重新一次一步走,快慢指標再次相遇的位置為環的第一個節點。

示例八

如何判斷兩個無環單鏈表是否相交,如果相交的話返回第一個相交的節點,不相交的話返回空,如果兩個連結串列的長度分別為N與M,請做到時間複雜度為 O ( N + M ) O(N+M) ,額外空間複雜度為 O ( 1 ) O(1)
分析:遍歷一遍兩個連結串列,如果N>M,則第一個連結串列從N-M處,第二個連結串列從頭節點開始遍歷,對比兩個節點是否相同。
這裡寫圖片描述

示例九

如何判斷兩個有環單鏈表是否相交,如果相交的話返回第一個相交的節點,不相交的話返回空,如果兩個連結串列的長度分別為N與M,請做到時間複雜度為 O ( N + M ) O(N+M) ,額外空間複雜度為 O ( 1 ) O(1)
分析:首先找到兩個連結串列的入環節點,如果入環節點相同,則按照無環連結串列找第一個相交節點的方法找到第一個相交點。如果入環節點不同可分為如下兩種型別。
這裡寫圖片描述
遍歷第一個環,若找不到第二個環的入環節點,則為情況一,若找到第二個環的入環節點則為情況二,情況二隨便返回任意一個入環節點均可。