您的位置:首页 > 理论基础 > 数据结构算法

笔试常考的数据结构-单链表操作实现

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

代码(C++):

[cpp] view
plaincopyprint?

//笔试面试单链表常用操作编程实现

#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(<span style="font-family: Arial, Helvetica, sans-serif;">merge_list_head</span><span style="font-family: Arial, Helvetica, sans-serif;">);</span>

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++:



运行结果:



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: