`
844604778
  • 浏览: 549734 次
文章分类
社区版块
存档分类
最新评论

笔试面试常考数据结构-单链表常用操作编程实现

 
阅读更多

单链表是笔试以及面试手写代码中常考的数据结构之一。下面实现了单链表的常见操作:创建单链表、删除节点、打印单链表(包括正向打印以及逆向打印)、反转单链表、找出单链表的倒数第K个节点、合并两个有序单链表等操作。


代码(C++):

//笔试面试单链表常用操作编程实现
#include <iostream>
#include <stack>
#include <cstdlib>

using namespace std;

//单链表节点数据结构定义
typedef struct link_node_s{
	int m_val;
	struct link_node_s *next;
}link_node_t,*link_list_t;

//函数:创建单链表(头插法)
link_list_t create_linklist(int *a,int n);

//函数:打印单链表(从头到尾)
void print_linklist(link_list_t head);

//函数:打印单链表(从尾到头)
void print_linklist_reverse(link_list_t head);

//函数:新建链表节点
link_list_t creart_linknode(int val);

//函数:删除链表中的某一个节点(前提条件:该节点一定存在)
//性能要求:在O(1)时间复杂度内实现
void delete_node_exist(link_list_t *head,link_list_t node_deleted);

//函数:删除链表中数据值等于给定值的节点
void delete_node(link_list_t *head,int val);

//函数:获得链表中的倒数第K个节点
link_list_t get_kth_node(link_list_t head,int k);

//函数:反转链表
link_list_t reverse_linklist(link_list_t head);

//函数:合并两个已排序的链表(递归方法实现)
link_list_t merge_linklist_recursive(link_list_t head1,link_list_t head2);

int main(){
	const int num1 = 8;
	const int num2 = 10;
	int *a = new int[num1];
	int *b = new int[num2];
	int *a_sorted = new int[num1];
	int *b_sorted = new int[num2];

	srand(1);
	for(int i = 0;i < num1;++i){
		*(a + i) = rand() % 100;
		*(a_sorted + i) = 50 - i * 2 + 8;
	}
	
	for(int i = 0;i < num2;++i){
		*(b + i) = rand() % 200;
		*(b_sorted + i) = 50 - i * 4 + 1;
	}

	cout << "**********创建链表测试**********" << endl;
	link_list_t list1 = create_linklist(a,num1);
	link_list_t list2 = create_linklist(b,num2);
	link_list_t list_sorted1 = create_linklist(a_sorted,num1);
	link_list_t list_sorted2 = create_linklist(b_sorted,num2);

	cout << "**********输出链表测试(正向输出)**********" << endl;
	cout << "链表1:" << endl;
	print_linklist(list1);
	cout << "链表1(已序):" << endl;
	print_linklist(list_sorted1);
	cout << "链表2(已序):" << endl;
	print_linklist(list_sorted2);

	cout << "**********输出链表测试(逆向输出)**********" << endl;
	print_linklist_reverse(list1);


	cout << "**********获取链表的倒数第K个节点测试**********" << endl;
	int k = 3;
	link_list_t kth_node = get_kth_node(list1,k);
	if(NULL == kth_node)
		cout << "链表中倒数第" << k << "个节点不存在" << endl;
	else
		cout << "链表中倒数第" << k <<"个节点是: " <<kth_node->m_val << endl; 

	k = 8;
	kth_node = get_kth_node(list1,k);
	if(NULL == kth_node)
		cout << "链表中倒数第" << k << "个节点不存在" << endl;
	else
		cout << "链表中倒数第" << k <<"个节点是: " <<kth_node->m_val << endl; 

	k = 11;
	kth_node = get_kth_node(list1,k);
	if(NULL == kth_node)
		cout << "链表中倒数第" << k << "个节点不存在" << endl;
	else
		cout << "链表中倒数第" << k <<"个节点是: " <<kth_node->m_val << endl; 

	cout << "**********删除链表中一定存在的节点测试(输入参数是要删除的节点指针)**********" << endl;
	link_list_t node_deleted = list1;
	while(node_deleted->m_val != *(a + 4))
		node_deleted = node_deleted->next;

	cout << "删除节点" << *(a + 4) << "之后的单链表:" << endl;
	delete_node_exist(&list1,node_deleted);
	print_linklist(list1);
	
	node_deleted = list1;
	while(node_deleted->m_val != *(a + 6))
		node_deleted = node_deleted->next;

	cout << "删除节点" << *(a + 6) << "之后的单链表:" << endl;
	delete_node_exist(&list1,node_deleted);
	print_linklist(list1);

	cout << "**********删除链表中值等于给定值的节点测试(不一定存在,输入参数是int型值)**********" << endl;
	const int val_deleted = 22;
	delete_node(&list1,val_deleted);
	cout << "删除值等于" << val_deleted << "之后的链表:" << endl;
	print_linklist(list1);

	cout << "**********合并链表测试**********" << endl;
	link_list_t merge_list_head = merge_linklist_recursive(list_sorted1,list_sorted2);
	print_linklist(merge_list_head);

	
	cout << "**********逆转链表测试**********" << endl;
	link_list_t head_reverse = reverse_linklist(merge_list_head);
	cout << "逆转之后的链表:" << endl;
	cout << "头节点:" << head_reverse->m_val << endl;
	print_linklist(head_reverse);
	
	return 0;
}

//函数:创建单链表(头插法)
link_list_t create_linklist(int *a,int n){
	link_list_t head = NULL;

	if(NULL == a || 0 == n)
		return NULL;

	for(int i = 0;i < n;++i){
		link_list_t new_node = creart_linknode(*(a + i));

		if(NULL == head){
			head = new_node;
		}
		else{
			new_node->next = head;
			head = new_node;
		}
	}

	return head;
}

//函数:新建链表节点
link_list_t creart_linknode(int val){
	link_list_t node = new link_node_t;
	node->m_val = val;
	node->next = NULL;

	return node;
}

//函数:打印单链表
void print_linklist(link_list_t head){
	link_list_t node = head;

	cout << "正向输出单链表" << endl;
	while(node != NULL){
		cout << node->m_val << " ";
		node = node->next;
	}
	cout << endl;

	return;
}

//函数:打印单链表(从尾到头)
void print_linklist_reverse(link_list_t head){
	stack<int> node_stack;
	link_list_t node = head;
	while(node != NULL){
		node_stack.push(node->m_val);
		node = node->next;
	}

	cout << "逆向输出单链表" << endl;
	while(!node_stack.empty()){
		cout << node_stack.top() << " ";
		node_stack.pop();
	}
	cout << endl;

	return;
}


//函数:删除链表中的某一个节点(前提条件:该节点一定存在)
//性能要求:在O(1)时间复杂度内实现
void delete_node_exist(link_list_t *head,link_list_t node_deleted){
	//算法思想:
	//通过拷贝要删除节点的后继节点的内容覆盖要删除节点的内容,然后删除要删除节点的后继节点即可
	//要考虑的特殊情况是:要删除的节点是链表尾部节点,仍然需要遍历链表
	if(NULL == head || NULL == node_deleted)
		return;

	//要删除的节点不是尾节点
	if(node_deleted->next != NULL){
		link_list_t next_node = node_deleted->next;
		node_deleted->m_val = next_node->m_val;
		node_deleted->next = next_node->next;

		delete next_node;
		next_node = NULL;
	}
	//链表中只有一个节点
	else if(*head == node_deleted){
		delete node_deleted;
		node_deleted = NULL;
		*head = NULL;
	}
	//要删除的节点是尾节点
	else{
		link_list_t node = *head;
		while(node->next != node_deleted)
			node = node->next;

		node->next = node_deleted->next;
		delete node_deleted;
		node_deleted = NULL;
	}

	return;
}

//函数:获得链表中的倒数第K个节点
link_list_t get_kth_node(link_list_t head,int k){
	//性能:只需遍历链表一遍即可
	//算法思想:设置两个指针,一个指向链表头部,一个指向第k个节点,然后两个指针同时向后移动,当第二个指针指向链表的尾节点时,第一个指针指向的节点便是倒数第K个节点
	//注意代码的鲁棒性,防止程序的崩溃
	if(NULL == head || k <= 0)
		return NULL;

	//设置两个指针
	link_list_t p1 = head,p2 = head;
	int i = 0;
	//第二个指针向前走k-1步
	while(i < k - 1 && p2->next != NULL){
		p2 = p2->next;
		++i;
	}
	//注意链表中总节点数小于K的情况
	if(i != k - 1 && NULL == p2->next)
		return NULL;

	//两个指针同时向后前进
	while(p2->next != NULL){
		p1 = p1->next;
		p2 = p2->next;
	}

	return p1;
}


//函数:反转链表
//返回值:反转之后的链表头节点
link_list_t reverse_linklist(link_list_t head){
	//链表为空或者只有一个节点
	if(NULL == head || NULL == head->next)
		return head;

	link_list_t prev_node = NULL,next_node,cur_node = head,head_reverse;
	while(cur_node != NULL){
		next_node = cur_node->next;
		if(NULL == next_node)
			head_reverse = cur_node;//原链表尾节点即逆转后链表的头节点
		cur_node->next = prev_node;
		prev_node = cur_node;
		cur_node = next_node;
	}

	return head_reverse;
}

//函数:删除链表中数据值等于给定值的节点
void delete_node(link_list_t *head,int val){
	if(NULL == head){
		cout << "Delete node failed :The node to be delete not exist!" << endl;
		return;
	}

	if(val == (*head)->m_val){
		link_list_t node = *head;
		*head = (*head)->next;
		delete node;
		return;
	}
	//首先判断该节点是否存在链表中
	link_list_t node = *head;
	while(node->next != NULL){
		if(val == node->next->m_val)
			break;
		node = node->next;
	}
	//存在满足条件的节点
	if(node->next != NULL){
		link_list_t node_delete = node->next;
		node->next = node_delete->next;
		delete node_delete;
	}
	else
		cout << "删除失败:链表中不存在值等于" << val << "的节点" << endl;

	return;
}

//函数:合并两个已排序的链表(递归方法实现)
link_list_t merge_linklist_recursive(link_list_t head1,link_list_t head2){
	if(NULL == head1)
		return head2;
	else if(NULL == head2)
		return head1;

	link_list_t merge_head = NULL;

	if(head1->m_val < head2->m_val){
		merge_head = head1;
		merge_head->next = merge_linklist_recursive(head1->next,head2);
	}
	else{
		merge_head = head2;
		merge_head->next = merge_linklist_recursive(head1,head2->next);
	}

	return merge_head;
}

测试平台:WIn8+Ubuntu12.04+Vim+G++:



运行结果:



分享到:
评论

相关推荐

    Java面试宝典和大学生面试宝典

    一般有点儿偏“硬”的 IT 公司会对 C++中指针的用法、数据结构考 得比较多。偏“软”的企业会对设计模式、模板着重一些。所以本书分 得很细,力求对各种 IT 公司的笔试题目做一个详尽的阐述。 作为求职者,笔试前你...

    高级C语言 C 语言编程要点

    77. 单链表的实现及其操作 391 78. 双向链表 395 79. 程序员数据结构笔记 399 80. Hashtable和HashMap的区别 408 81. hash 表学习笔记 410 82. C程序设计常用算法源代码 412 83. C语言有头结点链表的经典实现 419 84...

    免费下载:C语言难点分析整理.doc

    77. 单链表的实现及其操作 391 78. 双向链表 395 79. 程序员数据结构笔记 399 80. Hashtable和HashMap的区别 408 81. hash 表学习笔记 410 82. C程序设计常用算法源代码 412 83. C语言有头结点链表的经典实现 419 84...

    C语言难点分析整理.doc

    77. 单链表的实现及其操作 391 78. 双向链表 395 79. 程序员数据结构笔记 399 80. Hashtable和HashMap的区别 408 81. hash 表学习笔记 410 82. C程序设计常用算法源代码 412 83. C语言有头结点链表的经典实现 ...

    c语言难点分析整理,C语言

    77. 单链表的实现及其操作 391 78. 双向链表 395 79. 程序员数据结构笔记 399 80. Hashtable和HashMap的区别 408 81. hash 表学习笔记 410 82. C程序设计常用算法源代码 412 83. C语言有头结点链表的经典实现 419 84...

    高级进阶c语言教程..doc

    77. 单链表的实现及其操作 391 78. 双向链表 395 79. 程序员数据结构笔记 399 80. Hashtable和HashMap的区别 408 81. hash 表学习笔记 410 82. C程序设计常用算法源代码 412 83. C语言有头结点链表的经典实现 419 84...

    史上最强的C语言资料

    77. 单链表的实现及其操作 391 78. 双向链表 395 79. 程序员数据结构笔记 399 80. Hashtable和HashMap的区别 408 81. hash 表学习笔记 410 82. C程序设计常用算法源代码 412 83. C语言有头结点链表的经典实现 419 84...

    高级C语言详解

    77. 单链表的实现及其操作 391 78. 双向链表 395 79. 程序员数据结构笔记 399 80. Hashtable和HashMap的区别 408 81. hash 表学习笔记 410 82. C程序设计常用算法源代码 412 83. C语言有头结点链表的经典实现 419 84...

    C语言难点分析整理

    77. 单链表的实现及其操作 391 78. 双向链表 395 79. 程序员数据结构笔记 399 80. Hashtable和HashMap的区别 408 81. hash 表学习笔记 410 82. C程序设计常用算法源代码 412 83. C语言有头结点链表的经典实现 419 84...

    高级C语言.PDF

    C语言笔试-运算符和表达式 ....................................................................................................... 93 20. C语言编程准则之稳定篇 ............................................

Global site tag (gtag.js) - Google Analytics