在补习班上课2个多月了.今天上课老师讲了单链表的很多操作.由于之前一直是自学状态,涉猎单链表方面很少.所以听完感觉之前学习的真的是太少了,还需要好好努力去扩充自己的知识储备.
多题预警,与君共勉~~
首先说一下单链表的结构吧,链表分为数据域和指针域.指针域存放的是下一个结构体的指针.
也可以设置一个带有控制信息的链表,控制信息的链表除了含有普通的数据域和指针域除外,还含有一个另外的结构体,这个另外的结构题存储的是头尾节点的信息,以及链表的长度.
基础的链表增删查就不多罗嗦了,
在给出答案之前,先把问题给大家.先思考在查询答案对思维是一种锻炼哦~~
1.如何给一个链表排序?
2.合并两个链表,并且让合并后的链表有序
3.找到链表的倒数第n个节点并返回
4.链表翻转
5.判断两个链表是否有相交
6.给出一个链表,删除这个链表中给出的节点(你能想到用最短的时间的方法) 注:链表给出,删除的节点给出,如何去删除它
7找到环的交点.
如果没见过这几道题就先思考一下^_^
如何排序?(选择一个排序方法并使用库函数memcpy)
合并(创建一个新链,用排序模块)
找位置(用两个指针,一个跑n次,另一个在开始跑)
翻转(尾部删除.头部插入)
相交(两个指针分别指向不同的链表.同时跑,如果两个的next都为空的时候两个节点相同.说明相交)
删除(找到节点的next让两个节点的数据域交换,然后删除它的next)
交点(先让一个指针的速度是另一个的两倍,找到交点,然后让一个指针在交点跑,另一个在初始位置跑.相同的位置则说明相交点)
求交点得需要一个简单的证明:
首先定义一些长度一会证明,环的长度设为m
头到相遇的节点的长度为x
两个指针一个跑得速度是另一个的两倍
相遇慢指针走的长度设为z
那么快指针走的是2z
慢指针在圆上跑了y个单位.
z == x+y
2z - z == km(k = 1,2,3,...)(两者相遇的时候肯定一个在环里跑了k圈,而另一个还没到一圈)
现在让一个节点指向头,另一个指向相交节点,两者同时跑一个单位,如果走x个单位,那么一个指针在交点处,而另一个指针呢?
它也走了x个单位,但是换算一下 x == z-y
z == km 所以x == km-y是多少呢
正好走到了交点处!!!
废话不说,直接撸代码
我先把我的结构题和一些宏定义贴上来,
注:其中一些函数引用了Malloc,swap,pop,push等模块,可以当作伪代码来看,下一篇会帖出完整代码,亲测可运行
注:pop_back 尾部弹出,pop_front头部弹出,push_front头插,push_back尾插,Malloc分配内存(其实就是用的malloc)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TRUE (1)
#define FALSE (0)
#define ZERO (0)
#define ONLY_ONE (1)
typedef unsigned char Boolean;//c语言里没有bool类型所以定义一个
//控制信息
typedef struct list{
struct node *head;
struct node *tail;
int count;
}*List;
//节点信息
typedef struct node{
int data;
struct node *next;
}*p_node;
1:
void sort_list_descent(List *list) //降序排列
{
List_node *p_node = NULL;
List_node *q_node = NULL;
unsigned long data_size = 0;
if(list == NULL || list->count < TWO){
return ;
}
// List_node *p = list->head;
// p->next = NULL;
// ((unsigned long)&(((List_node *)0)->next))
// sizeof(List_node) - sizeof(List_node *);
// int data; // 0 1 2 3
// // 4 5 6 7
// struct List_Node *next; // 8 9 10 11
// 12 13 14 15
//
data_size = get_data_size(); //求得数据区域得大小
for(p_node = list->head; p_node->next; p_node = p_node->next){
for(q_node = p_node->next; q_node ; q_node = q_node->next){
if(p_node->data < q_node->data){
swap(p_node, q_node, data_size); //交换函数
}
}
}
}
2:
List *merge_two_lists(List *list1, List *list2) //合并两个有序链表
{
List *result = NULL;
List_node *list1_move = NULL;
List_node *list2_move = NULL;
if(list1 == NULL || list2 == NULL){
return result;
}
result = init_list(); //结果链表得初始化
list1_move = list1->head;
list2_move = list2->head;
// | head | tail | count |
// \ / n-> n - 1
// \ /
// node1->node2->node3
//
//
// | head | tail | count |
// \ / n-> n - 1
// \ /
// node1->node2->node3
//
//如果两个链表都没有遍历完,进行比较
while(list1_move != NULL && list2_move != NULL){
if(list1_move->data <= list2_move->data){
push_back(result, list1_move->data);
list1_move = list1_move->next;
}else{
push_back(result, list2_move->data);
list2_move = list2_move->next;
}
}
//当两个链表中任何一个遍历结束,则把另外一个进行尾部添加
while(list2_move != NULL){
push_back(result, list2_move->data);
list2_move = list2_move->next;
}
while(list1_move != NULL){
push_back(result, list1_move->data);
list1_move = list1_move->next;
}
return result;
}
3:p_node find_revise_node(List list,int num)
{
p_node p = list->head;
p_node q = list->head;
if(list == NULL || num == 0){
return NULL;
}
while(num--){
p = p->next;
}
while(p){
q = q->next;
p = p->next;
}
return q;
}
4.<pre name="code" class="cpp">List reverse_list1(List list)//逆置链表
{
p_node p = list->head;
if(list == NULL || list->count < 2)
{
return NULL;
}
List L;
L = init_list();
while(p){
push_front(L,p->data);
p = p->next;
}
return L;
}
5:
Boolean is_list_intersect(List list1,List list2)//判断链表是否相交
{
if(list1 == NULL || list2 == NULL)
return FALSE;
return list1->tail == list2->tail;
}
6
void delete_one_node(List list,int value)//O(1)时间复杂度删除节点
{
p_node p = list->head->next;
if(list == NULL){
return ;
}
while(p->data != value && p){
p = p->next;
}
if(p != list->tail){
p->data = p->next->data;
p->next = p->next->next;
}
else
pop_back(list);
list->count--;
}