[数据结构学习]单链表常用操作
2013-11-08 23:37
513 查看
想到数据结构和算法的学习就头疼,对于我一个学java的来说,真后悔当初没有好好学了(c、c++的知识基本也快忘光光了),
可是还得硬着头皮学呀(考虑到明年找工作的事儿),就先从单链表下手吧,
想想若是让我这个新手一个一个的写算法去实现,似乎还不太现实。
还是先参考别人的把基础搞清楚,以后再慢慢深入学习比较合适~
参考原文:http://blog.csdn.net/xiajun07061225/article/details/9246573
注:自己只是在此基础上加了 头插法和尾插法建立单链表(带头结点)、单链表插入结点、单链表清空这三个操作。
话不多说,开始单链表的学习->Go
代码如下:
可是还得硬着头皮学呀(考虑到明年找工作的事儿),就先从单链表下手吧,
想想若是让我这个新手一个一个的写算法去实现,似乎还不太现实。
还是先参考别人的把基础搞清楚,以后再慢慢深入学习比较合适~
参考原文:http://blog.csdn.net/xiajun07061225/article/details/9246573
注:自己只是在此基础上加了 头插法和尾插法建立单链表(带头结点)、单链表插入结点、单链表清空这三个操作。
话不多说,开始单链表的学习->Go
代码如下:
#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); //函数:创建单链表(头插法,带头结点) link_list_t create_linklist2(int *a,int n); //函数:创建单链表(尾插法,带头结点) link_list_t create_linklist3(int *a,int n); //函数:打印单链表(从头到尾) void print_linklist(link_list_t head); //函数:打印单链表(从头到尾,带头结点) void print_linklist2(link_list_t t); //函数:打印单链表(从尾到头) void print_linklist_reverse(link_list_t head); //函数:新建链表节点 link_list_t creart_linknode(int val); //函数:带头结点的单链表插入操作 void insert_linklist(link_list_t *t,int i,int val); //函数:清空单链表 void empty_linklist(link_list_t *t); //函数:删除链表中的某一个节点(前提条件:该节点一定存在) //性能要求:在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]; /**********************简单测试********************/ //测试1 int *c = new int[num2]{1,6,3,7,9,3,4,5,6,7}; link_list_t list3 = create_linklist(c,num2); print_linklist(list3);//因为是头插法,所以会逆序输出,7是头结点 //测试2 link_list_t list4 = create_linklist2(c,num2); print_linklist2(list4); //测试3 link_list_t list5 = create_linklist3(c,num2); print_linklist2(list5); //测试4 insert_linklist(&list5,0,99); print_linklist2(list5); //测试5 empty_linklist(&list5); print_linklist2(list5); /***************************************************/ //生成创建链表所需数据 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 << "链表2:" << endl; print_linklist(list2); 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); return 0; } //函数:创建单链表(头插法,不带头结点) //a为指向整型数组的指针,n为链表的长度 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 create_linklist2(int *a,int n){ if(NULL == a || 0 == n) return NULL; //创建头结点 link_list_t head=new link_node_t; head->next=NULL; for(int i = 0;i < n;++i){ link_list_t new_node = creart_linknode(*(a + i)); new_node->next = head->next;//要插入的新结点指向链表的第一个结点 head->next = new_node; } return head; } //函数:创建单链表(尾插法,带头结点) //需要设置一个尾指针r link_list_t create_linklist3(int *a,int n){ if(NULL == a || 0 == n) return NULL; //创建头结点 link_list_t head=new link_node_t; head->next=NULL; //设置尾指针 link_list_t r=head; for(int i = 0;i < n;++i){ link_list_t new_node = creart_linknode(*(a + i)); r->next=new_node; r=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_linklist2(link_list_t t){ t=t->next; cout << "正向输出单链表" << endl; while(t != NULL){ cout << t->m_val << " "; t = t->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; } //函数:带头结点的单链表插入操作 //前提:插入位置小于表长 void insert_linklist(link_list_t *t,int i,int val){//在第i个位置插入结点,该结点数据域为val link_list_t s=*t; if(s->next==NULL){ return; } int n=0; while(n<i){ s=s->next; n++; } //此时,t指向第i-1个结点 link_list_t node=new link_node_t; node->m_val=val; node->next=s->next; s->next=node; return; } //函数:清空单链表 void empty_linklist(link_list_t *t){ link_list_t s=*t; link_list_t u; while(s->next!=NULL){ u=s->next; s->next=u->next; delete u; u=NULL; } } //函数:删除链表中的某一个节点(前提条件:该节点一定存在) //性能要求:在O(1)时间复杂度内实现 void delete_node_exist(link_list_t *head,link_list_t node_deleted){//注意head参数为指针类型 //算法思想: //通过拷贝要删除节点的后继节点的内容覆盖要删除节点的内容,然后删除要删除节点的后继节点即可 //要考虑的特殊情况是:要删除的节点是链表尾部节点,仍然需要遍历链表 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;//同时指向NULL;因为delete一个指针之后,只是回收指针指向位置的空间,而指针本身的值不变.你需要手工将其赋值为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; } //函数:删除链表中数据值等于给定值的节点 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; node=NULL; 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; node_delete=NULL; } else cout << "删除失败:链表中不存在值等于" << val << "的节点" << endl; 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; } //函数:合并两个已排序的链表(递归方法实现) 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; }
相关文章推荐
- 笔试面试常考数据结构-单链表常用操作编程实现
- 数据结构学习(二)——单链表的操作之头插法和尾插法创建链表
- 数据结构学习一(单链表的操作)
- 数据结构学习笔记(二) 链表之单链表的基本操作
- 笔试面试常考数据结构-单链表常用操作编程实现
- 数据结构学习(三)——单链表的操作之查找、删除、插入。
- 笔试面试常考数据结构-单链表常用操作编程实现
- 数据结构学习(二)——单链表的操作之头插法和尾插法创建链表
- 数据结构学习(二)——单链表的操作之头插法和尾插法创建链表
- 《数据结构》 单链表常用操作代码集合
- 算法与数据结构学习 10 链表操作
- C语言数据结构单链表的一些基本操作
- Php常用文件操作函数,正则表达式,个人学习总结
- 《数据结构》 定长顺序串常用操作代码集合
- ucLinux内核常用数据结构和操作
- Redis常用数据结构和操作
- ThinkPHP学习笔记(六)常用的连贯操作和模版的使用
- 数据结构复习第一天单链表的操作集合
- C数据结构 单链表操作
- MFC学习笔记之:列表框(ListBox) 常用的的操作详解