引言

在上一篇博客数据结构1.单链表中,我们对链表相对数组的优缺点进行了比较。
而且,我们发现,链表是一种物理存储单元上非连续、非顺序的存储结构,所以,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
若是想要对链表中的其中一个元素进行操作,通常都需要p_node = p_node->next;的循环进行。

计算机科学领域的任何问题,都可以通过增加一个间接中间层来解决。
Any problems in computer science can be soved by another layer of indirection.

所以,我们在定义这个链表的时候,可以给链表加上一层控制信息。如下:

* 本文的所有源程序可以在single_control_list上得到。*

一、链表数据类型的定义

/*链表数据类型定义*/struct List_node;    //声明一个类型//链表控制信息
typedef struct List
{struct List_node *head;    //指向链表头部struct List_node *tail;    //指向链表尾部int              count;    //链表节点数量
}List;//链表节点信息
typedef struct List_node
{int               data;    //数据域struct List_node *next;    //指针域
}List_node;

这样我们可以看到,已经可以直接获取到链表节点个数以及指向尾部节点的指针。我们可以用来做什么呢?

二、链表的接口:

/********链表的接口********/List      *init_list(void)                                 ;    //1.  链表的初始化
void      destroy_list(List **list)                        ;    //2.  链表的销毁
Boolean   push_front(List *list, int value)                ;    //3.1 头部插入
Boolean   push_back(List  *list, int value)                ;    //3.2 尾部插入
Boolean   pop_front(List *list)                            ;    //4.1 头部删除
Boolean   pop_back(List *list)                             ;    //4.2 尾部删除
List_node *find_node(List *list, int value)                ;    //5.1 链表的查找
List_node *find_revise_node(List *list, int num)           ;    //5.2 找到链表的倒数第num个节点
List_node *find_mid_node(List *list)                       ;    //5.3 找到链表的中间节点
void      modify_node(List *list, int value)               ;    //6.1 链表节点的修改
Boolean   insert_node(List *list, int index, int value)    ;    //6.2 链表节点的插入(下标)
void      delete_one_node(List *list, List_node *node)     ;    //6.3 在O(1)的时间复杂度删除节点
void      sort_list_ascend(List *list)                     ;    //7.1 升序
void      sort_list_descent(List *list)                    ;    //7.2 降序排列
void      show_list(List *list)                            ;    //8.1 显示链表信息
void      reverse_show_list(List *list)                    ;    //8.2 逆序输出链表信息
int       get_list_count(List *list)                       ;    //9.  得到链表节点数量
List      *merge_two_lists(List *list1, List *list2)       ;    //10.  合并两个有序链表
List      *merge_two_lists_recure(List *list1, List *list2);    //11.  合并两个有序链表(递归)
List      *reverse_list(List *list)                        ;    //12.  逆置一个链表
List      *list_dump(List *list)                           ;    //13.  链表的拷贝
Boolean   is_list_intersect(List *list1, List *list2)      ;    //14.  判断链表是否有交点
List_node *get_first_common_node(List *list1, List *list2) ;    //15.  得到第一个交点
Boolean   has_circle(List *list)                           ;    //16.  判断一个链表是否有环
List_node *find_circle_first_node(List *list)              ;    //17.  找到带环链表的环入口节点

我们将这些都放入ctl_list.h文件当中,包括链表的定义,链表的接口,一些用到的宏定义。

为了能够方便的进行程序的设计,我们仍旧采用包裹函数的方式对某些操作进行简化:

/*接口包裹函数定义*/static void *Malloc(size_t size);
static List_node *Create_node(void);
static void Swap(void *a, void *b, int length);
static void Rev_show_list(List_node *node);

我们常用到的操作函数定义如下:

/*接口包裹函数实现*/static void *Malloc(size_t size)
{void *result = malloc(size);if(result == NULL){fprintf(stderr, "the memory is full\n");exit(1);}return result;
}static List_node *Create_node(void)    //创建链表节点
{List_node *node = (List_node *)Malloc(sizeof(List_node));bzero(node, sizeof(List_node));return node;
}static void Swap(void *a, void *b, int length)
{void *temp = Malloc(length);memcpy(temp, a, length);memcpy(a, b, length);memcpy(b, temp, length);free(temp);
}static void Rev_show_list(List_node *node)
{//要打印当前节点,先打印其后续节点if(node != NULL){rev_show_list(node->next);printf("%d ", node->data);    }
}

宏定义如下:

/*控制链表宏定义*/#define TRUE               (1)
#define FALSE              (0)
#define ZERO               (0)
#define ONLY_ONE           (1)
#define TWO                (2)
#define get_data_size()    ((unsigned long)&(((List_node *)0)->next)) 

三、链表接口的实现

//1.链表的初始化
//      | head | tail | count |
//          \      /      0
//           \    /
//            NULL
List      *init_list(void)
{List *list = (List *)Malloc(sizeof(List));bzero(list, sizeof(List));    //全部清零return list;
}
//2. 链表的销毁
//              list
//             /
//         list_head
//          /
//      | head | tail | count |
//          \         \   n + 1
//
//            \          \
//            node->node2->node3void      destroy_list(List **list)
{if(list == NULL || *list == NULL){return ;}//  链表删除步骤://  1.删除链表节点信息;while((*list)->count){   //头部删除链表节点pop_front(*list);}//  2.删除链表控制信息.free(*list);*list = NULL;
}
//3.1 头部插入
Boolean   push_front(List *list, int value)
{List_node *node = NULL;if(list == NULL){ return FALSE;}   //创建节点并赋值node = create_node();node->data = value;//   case1://      | head | tail | count |//          \      /      1//           \    ///            nodeif(list->count == ZERO){list->tail = node;}else{//   case2://      | head |              tail | count |//          \                 /       n + 1//           \               ///            node->node2->node3node->next = list->head;}list->head = node;list->count++;return TRUE;
}
//3.2 尾部插入
Boolean   push_back(List  *list, int value)
{List_node *node = NULL;if(list == NULL){return FALSE;}node = create_node();node->data = value;//   case1://      | head | tail | count |//          \      /      1//           \    ///            nodeif(list->count == ZERO){list->head = list->tail = node;}else{//   case2://      | head |              tail | count |//          \                 /       n + 1//           \               ///            node1->node2->nodelist->tail->next = node;list->tail = node;}list->count++;return TRUE;
}

//4.1 头部删除
Boolean   pop_front(List *list)
{List_node *p_node = NULL;if(list == NULL || list->count == ZERO){return FALSE;}//   case1://      | head | tail | count |//          \      /      1->0//           \    ///            node//   case2://      | head |              tail | count |//          \                 /       n-> n - 1//           \               ///            node1->node2->node3p_node = list->head;if(list->count == ONLY_ONE){list->head = list->tail = NULL; }else{list->head = list->head->next;}free(p_node);list->count--;return TRUE;
}
//4.2 尾部删除
Boolean   pop_back(List *list)
{List_node *p_node = NULL;if(list == NULL || list->count == ZERO){ return FALSE;}//   case1://      | head | tail | count |//          \      /      1->0//           \    ///            node//   case2://      | head |              tail | count |//          \                 /       n-> n - 1//           \               ///            node1->node2->node3p_node = list->head; if(list->count == ONLY_ONE){    list->head = list->tail = NULL;free(p_node);}else{//判断倒数第二个?//   p_node->next == list->tailwhile(p_node->next != list->tail){p_node = p_node->next;}free(list->tail);list->tail = p_node;p_node->next = NULL;}list->count--;return TRUE;
}
//5.1 链表的查找
List_node *find_node(List *list, int value)
{if(list == NULL){return NULL;}List_node *p = list->head;while(p != NULL){if(p->data == value){printf("found the value: %d\n", value);return p;}p = p->next;}printf("No found!");return NULL;
}
//5.2 找到链表的倒数第num个节点
List_node *find_revise_node(List *list, int num)
{List_node *move = NULL;int move_count = 0;//move + num == countif(list == NULL || num <= 0 || num > list->count){return NULL;}    move = list->head;//移动的步长move_count = list->count - num;while(move_count--){move = move->next;}return move;
}
//5.3 找到链表的中间节点// 1.) 快慢指针:////       f  每次移动2步, s 每次移动1步//       10  23  5  15  50  67  45  32  82//// 2.)   10 /  2 == 5//       10 >> 1 == 5////       0000 1010   10//            10 >> 1//       0000 0101   5
List_node *find_mid_node(List *list)
{List_node *move = NULL;int move_count = 0;if(list == NULL){return NULL;}move = list->head;move_count = list->count >> 1;while(move_count--){move = move->next;}return move;
}
//6.1 链表节点的修改
void modify_node(List *list, int index, int value)
{int count = index;List_node *p = list->head;if(list == NULL || index >= list->count || index < 0){return ;while(count--){p = p->next;}p->data = value;
}
//6.2链表节点的插入
Boolean insert_node(List *list,int index, int value)
{if(list == NULL || index > list->count || index < 0){return FALSE;}//在最后则尾部插入if(index == list->count){return push_back(list, value);}//在最前则头部插入if(index == 0){return push_front(list, value);}int count =  index -1;List_node *p_node = list->head;//创建新节点List_node *node = create_node();node->data = value;//寻找需插入的节点位置while(count--){p_node = p_node->next;}//进行插入node->next = p_node->next;p_node->next = node;list->count++;return TRUE;
}
//6.3 在O(1)的时间复杂度删除节点//由于是单链表,无法获取到前一个节点的位置,//所以,我们在这里用后一个节点代替我们所需的节点。
void      delete_one_node(List *list, List_node *node)
{if(list == NULL || node == NULL){return ;}//尾部删除if(node == list->tail){pop_back(list);return ;}List_node *p = node->next;//保存下一个节点位置node->data = node->next->data; //这个节点作为后一个的替代node->next = node->next->next; //直接指向下一个节点的后面free(p);list->count--;
}

//7.1 升序排列//我们在这里用到了一种新的办法求我们的结构体大小,定义在宏里:// ((unsigned long)&(((List_node *)0)->next))//    //                    (List_node *)0          //指向首地址在0的List_node的指针//                   ((List_node *)0)->next)  //取next则指向了它的下一个//                 &(((List_node *)0)->next)) //取地址,得到的是这个地址,由于首地址,则正好是大小// ((unsigned long)&(((List_node *)0)->next)) //unsigned long 类型转换,得到就是大小// 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  15void      sort_list_ascend(List *list)
{List_node *p_node = NULL;List_node *q_node = NULL;unsigned long data_size = 0;if(list == NULL || list->count < TWO){return ;}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);                }}}
}

//7.2 降序排列//和升序类似
void      sort_list_descend(List *list)
{List_node *p_node = NULL;List_node *q_node = NULL;unsigned long data_size = 0;if(list == NULL || list->count < TWO){return ;}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);                }}}
}
//8.1 显示链表信息
void      show_list(List *list)
{List_node *p_node = NULL;if(list != NULL && list->count != ZERO){ for(p_node = list->head; p_node; p_node = p_node->next){ printf("%d ", p_node->data);}printf("\n");}
}
//8.2 逆序输出链表信息
void      reverse_show_list(List *list)
{if(list == NULL || list->count == ZERO){return ;}  // .h中定义的递归(先递归再输出)Rev_show_list(list->head);printf("\n");
}
//9 得到链表节点数量//这是一个有控制信息的链表,有关于节点数量的变量
int       get_list_count(List *list)
{if(list == NULL){ return -1;}return list->count;
}
///10 合并两个有序链表//l1    | head |              tail | count |//          \                 /       n-> n - 1//           \               ///            node1->node2->node3//////l2    | head |              tail | count |//          \                 /       n-> n - 1//           \               ///            node1->node2->node3//
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;//如果两个链表都没有遍历完,进行比较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;
}

//11//合并两个有序链表(递归)//   //l1            node1->node2->node3////     l->node1->node4...//    //l2            node4->node5->node6//
List      *merge_two_lists_recure(List *list1, List *list2)
{List *node = NULL;List *l  = init_list();List *l1 = list1;List *l2 = list2;if(l1->count == 0){return list2;}if(l2->count == 0){return list1;}//若l1当前head满足较小情况,将l指向l1,让l1指向l1的下一个节点,进入递归比较l1->head->next形成的链表与l2再进行比较,返回的node链表是后面节点的新链表;if(l1->head->data < l2->head->data){l->head = l1->head;l1->head = l1->head->next;l1->count --;node = merge_two_lists_recure(l1, l2);}else{l->head = l2->head;l2->head = l2->head->next;l2->count--;node = merge_two_lists_recure(l1, l2);}//完成递归后,l指向node组成的新链表;l->head->next = node->head;l->count = node->count +1;return l;
}

//12 逆置一个链表//因为会改变结构,为了不失去对后面的节点的信息,使用了三个指针,交换前两个,不丢失第三个 。////      | head |              tail | count |//          \                   \      n-> n - 1//           \                   \//            node1->node2->node3->node4//             |      |       |//             p      q       m////            node1<-node2 node3->node4//             |      |       |      |//             p      q       m      |//                    p       q      m   //List      *reverse_list(List *list)
{List_node *p_node = NULL;List_node *q_node = NULL;List_node *m_node = NULL;if(list == NULL || list->count < TWO){return list;} //两个节点if(list->count == TWO){list->tail->next = list->head;list->head->next = NULL;}else{    //三个节点p_node = list->head;q_node = p_node->next;m_node = q_node->next;p_node->next = NULL;do{q_node->next = p_node;   //让中间指针的next指向前一个p_node = q_node;    //指针整体向后搬移q_node = m_node;m_node = m_node->next;}while(m_node != NULL);q_node->next = p_node;}//交换头尾指针swap(&(list->head), &(list->tail), sizeof(List_node *));return list;
}
//13 链表的拷贝//使用了尾插法依次将元素插入
List      *list_dump(List *list)
{List * new_list = init_list();List_node * node = list->head;for(node = list->head; node; node = node->next){push_back(new_list, node->data);}return new_list;
}
//14 判断链表是否有交点//若两个链表有交点,则尾节点一定是同一个。////  l1-> => => =>//                \//                 \     //                 /  => => => => => =>//  l2-> => => => //
Boolean   is_list_intersect(List *list1, List *list2)
{if(list1 == NULL || list2 == NULL){return FALSE;}
//    if( list1->tail == list2->tail){printf("intersect\n");return TRUE;}else{printf("nothing\n");return FALSE;}
}
//15 得到第一个交点//             l1 =>//                    \     //                    /   => => => => => =>//     l2 => => => => //     长度不等,先获得两个链表都离相遇点长度相等的地方开始依次比较。
List_node *get_first_common_node(List *list1, List *list2)
{int list1_len = 0;int list2_len = 0;int distance = 0;List_node *p_node = NULL;List_node *q_node = NULL;if(!is_list_intersect(list1, list2)){    //判断两个链表是否有交点return NULL;}list1_len = list1->count;list2_len = list2->count;p_node = list1->head;q_node = list2->head;//判断较长链表并首先进行移动if(list1_len >= list2_len){distance = list1_len - list2_len;while(distance--){ p_node = p_node->next;}}else{distance = list2_len - list1_len;while(distance--){q_node = q_node->next;}}//依次对对应节点进行判断是否相等,如果相等则是第一个相交节点while(p_node != q_node){p_node = p_node->next;q_node = q_node->next;}return p_node;
}
//16 判断一个链表是否有环////   - - - 、  //          \    - - - - 、//           \ /          |//            \          ///             ` - - - -//
Boolean has_circle(List *list)
{List_node *p = list->head;  //slowList_node *q = list->head;  //fastwhile(p != NULL && q != NULL && q->next !=NULL){p = p->next;        //一次一步q = q->next->next;  //一次两步//如果有环,则一定会相遇if(p == q){printf("we found circle!\n");return TRUE;}}printf("no circle!\n");return FALSE;
}
//17 找到带环链表的环入口节点////   - - - 、  //          \    - - - - 、//           \ /          |//            \          ///        入口点 ` - -*- -//                   \//                     相遇点//            |<-x->|//  |<---a--->|<-----r---->|//  |<----------L--------->|// 我们设整个链表长L,入口点与相遇点长x,起点到入口点长度为a;// 快指针走的长度是慢指针的2倍,由于快指针可能不止走了一圈;// 慢指针走了s步,即快指针走了2s步。//// ∵ 2s = s + nr ;// ∴ s = nr;////   a + x = nr//   a + x = nr = (n-1)r + r =  (n-1)r + L -a//   a = (n-1)r + (L -a -x)//   链表从头到环入口点长度 = (n -1)环长 + 相遇点到环入口长度//   所以, 从链表头和相遇点各设一个一步长的指针,必定会在相遇点回合。//
List_node *find_circle_first_node(List *list)
{List_node * entry = NULL;if(!has_circle(list)){return NULL;}List_node *p = list->head;  //slowList_node *q = list->head;  //fastwhile(p != NULL && q != NULL && q->next !=NULL){p = p->next;q = q->next->next;if(p == q){break;    //相遇点p和q}}//p为相遇点开始q = list->head;   //q从链表头开始while(q != p){p =p->next;q =q->next;}printf("we found the node is %d\n", q->data);return q;
}

四、测试功能

测试代码:

#include "list.h"int main()
{int i = 0;int num = 0;List *list = NULL;List *list1 = NULL;List *list2 = NULL;List_node * node = NULL;printf("1.init_list:\n");list = init_list();list1 = init_list();list2 = init_list();printf("3.1 list1 push_front :\n");for(i = 0; i < 6; i++){push_front(list1, rand()%100);}show_list(list1);printf("3.2 list2 push_back:\n");for(i = 0; i < 4; i++){push_back(list2, rand()%100);}show_list(list2);printf("4.1 list1 pop_front:\n");pop_front(list1);show_list(list1);printf("4.2 list2 pop_back:\n");pop_back(list2);show_list(list2);printf("7.1 sort_list1_ascend:\n");                   sort_list_ascend(list1);                  show_list(list1);printf("7.2 sort_list2_descend:\n");                   sort_list_descend(list2);                  show_list(list2);printf("12 reverse_list2:\n");reverse_list(list2);show_list(list2);#if 0printf("10. list : merge_two_lists(list1, list2):\n");list = merge_two_lists(list1, list2);show_list(list);
#endif#if 1printf("11. list : merge_two_lists_recure(list1, list2):\n");list = merge_two_lists_recure(list1, list2);show_list(list);
#endifprintf("8.1 show_list(list);\n");      show_list(list);printf("8.2 reverse_show_list(list);\n");reverse_show_list(list);
#if 1 printf("find_node:\n");printf("which one?(value to find)\n"); scanf("%d",&num);printf("found num of list is :%d \n",find_node(list, num)->data);
#endif#if 1printf("find_revise_node:\n");     printf("which one index ?(reverse)\n"); scanf("%d",&num);printf("reverse num of list is :%d \n",find_revise_node(list, num)->data);
#endifprintf("5.3 find_mid_node(list):\n") ;printf("%d \n",find_mid_node(list)->data);printf("9. get_list_count:\n"); printf("the count of list is :%d\n", get_list_count(list));#if 1  printf("6.3 delete_one_node:");printf("which one?(to delete)\n"); scanf("%d",&num);node = create_node();node = find_node(list,num);delete_one_node(list, node);show_list(list);
#endif#if 1printf("6.1 modify_node :\n");modify_node(list, 1, 26);show_list(list);
#endif#if 1printf("6.2 insert_node: \n");insert_node(list, 2, 18);show_list(list);
#endif #if 1printf("16. has_circle:\n");//list->head->next->next->next->next->next = list->head->next;if(has_circle(list)){printf("17 find_circle_first_node:\n");find_circle_first_node(list);}
#endifprintf("13. list1:list_dump(list)\n");list1 = list_dump(list);printf("list1: ");show_list(list1);printf("14. is_list_intersect:\n");if(is_list_intersect(list1, list)){printf("the common node: %d\n",get_first_common_node(list1, list));}printf("2. destroy_list:\n");destroy_list(&list1);destroy_list(&list2);destroy_list(&list);return 0;
}

运行结果:

root@aemonair:/ctl_list# ./bin/list
1.init_list:
3.1 list1 push_front :
35 93 15 77 86 83
3.2 list2 push_back:
86 92 49 21
4.1 list1 pop_front:
93 15 77 86 83
4.2 list2 pop_back:
86 92 49
7.1 sort_list1_ascend:
15 77 83 86 93
7.2 sort_list2_descend:
92 86 49
12 reverse_list2:
49 86 92
11. list : merge_two_lists_recure(list1, list2):
15 49 77 83 86 86 92 93
8.1 show_list(list);
15 49 77 83 86 86 92 93
8.2 reverse_show_list(list);
93 92 86 86 83 77 49 15
find_node:
which one?(value to find)
92
found the value: 92
found num of list is :92
find_revise_node:
which one index ?(reverse)
2
reverse num of list is :92
5.3 find_mid_node(list):
86
9. get_list_count:
the count of list is :8
6.3 delete_one_node:which one?(to delete)
92
found the value: 92
15 49 77 83 86 86 93
6.1 modify_node :
15 26 77 83 86 86 93
6.2 insert_node:
15 26 18 77 83 86 86 93
16. has_circle:
no circle!
13. list1:list_dump(list)
list1: 15 26 18 77 83 86 86 93
14. is_list_intersect:
nothing
2. destroy_list:

总结

至此。我们完成了对带控制信息链表的定义,实现,测试;
我们会发现加上控制信息之后,一些操作被封装起来,有可能更加便捷。
这是一种思路,一种方法。
以上解法也不一定是最简便快捷的,只是其中一种实现而已。
我们还将继续对数据结构进行进一步的探讨。

数据结构2.带控制信息的链表相关推荐

  1. 数据结构实验--带环、相交链表问题

    一.问题描述: 基于课程上机关于单链表的作业,要求进一步实现以下需求: 1.构造链表后,将元素值为 m 和 n(从键盘输入,如有多个相同元素值,仅考虑首个出现的元素)的节点建立连接,注意判断节点出现的 ...

  2. 【JY】YJK前处理参数详解及常见问题分析:控制信息(二)

    点击蓝字  求求关注 [写在前文] 本文介绍计算控制信息之控制信息. [计算信息参数详解] 一.控制信息 A区参数详解 1.水平力与整体坐标夹角 该参数为地震作用.风荷载计算时的X正向与结构整体坐标系 ...

  3. 求两门成绩平均c语言,数据结构课的作业 要求用链表实现学生的学号 姓名 两门课的成绩 同时求出课程的平均成绩...

    数据结构课的作业 要求用链表实现学生的学号 姓名 两门课的成绩 同时求出课程的平均成绩 关注:69  答案:2  mip版 解决时间 2021-02-04 09:43 提问者孤城古巷 2021-02- ...

  4. 数据结构与算法之线性结构链表

    数据结构与算法之线性结构链表 这一篇文章主要介绍的是通过java实现单链表.循环链表和双向循环链表,仅供自己复习使用,如有什么不足之处,欢迎指出. 单链表: package xianxingjiego ...

  5. 计算机网络中的协议数据单元的控制信息主要包括哪些内容

    在计算机网络的数据传输过程中会对数据进行封装,俗称加头(链路层还会加尾),增加的控制信息主要包括以下内容: 地址(Address):用来标识发送端或接收端 差错检测编码(Error-detecting ...

  6. Algorithms_基础数据结构(04)_线性表之链表_单向循环链表约瑟夫环问题

    文章目录 大纲图 链表的经典面试题目 如何设计一个LRU缓存淘汰算法 约瑟夫问题 结构 分析 大纲图 链表的经典面试题目 如何设计一个LRU缓存淘汰算法 tip:单向链表 约瑟夫问题 N个人围成一圈, ...

  7. 数据结构与算法(C++)– 链表(Link)

    数据结构与算法(C++)– 链表(Link) 1.基础知识 表:把具有相同类型的序列 A0, A1, A2, - An 称为表 .n 是表的大小,n=0 称为空表. A0没有前驱,An没有后继. 前驱 ...

  8. 带表头节点单链表及其基本应用

    带表头节点单链表及其基本应用 结构体及其宏定义和所需要的C语言库 #include <stdio.h> #include <stdlib.h> #define ERROR 0 ...

  9. 数据结构与算法之反转单向链表和双向链表

    数据结构与算法之反转单向链表和双向链表 目录 反转单向链表和双向链表 1. 反转单向链表和双向链表 题目描述 代码实现 public class Code_ReverseList {public st ...

最新文章

  1. Android防止系统休眠
  2. vue里面怎么删除部分页面_基于VUE选择上传图片并页面显示(图片可删除)
  3. 服务器光信号闪红灯是什么意思,路由器光信号闪红灯是什么意思
  4. Java匿名内部类总结
  5. 4.Vue 模板语法
  6. TensorFlow(八)激活函数
  7. php基础教程 第十一步 面向对象补充
  8. cdi 2.7.5_集成测试CDI 1.0和Spring 3.1中的作用域bean
  9. 翼方健数邓振:“DRG+AI”助力实现医院精细化管理
  10. vue3 Cannot find module ‘path‘. 找不到模块‘path‘
  11. 全新一代云服务器S6,重新定义性价比
  12. 劝你们,千千千万不要当一个程序员!!!!!!
  13. 循序渐进之Spring AOP(3) - 配置代理
  14. 润乾报表-数据源的选取不能选视图
  15. sqlmap安装和使用
  16. 中央企业经营管理一体化总体框架
  17. java网站渗透测试_如何进行Web渗透测试
  18. 代写python代码一般多少钱_代写代码一般多少钱(专业解读)
  19. threejs 720/360全景工具开发心得
  20. 中文解释“GetLastError()返回值”---错误码大全

热门文章

  1. mysql情况数据库表数据函数_mysql数据库表单查询和函数的使用
  2. AppStore上线规则
  3. 国内云服务器哪家好?
  4. 給windowsXP穿上Linux Ubuntu的漂亮馬甲 1
  5. HTML:如何设置网页标题上的图标
  6. 浏览器通过原生JS实现录音功能
  7. 使用markdownpad生成目录
  8. OPPOR9Plus系列通刷刷机包精简包_OPPOR9Plus线刷包救砖包_OPPOR9Plus纯净刷机包_OPPOR9Plus刷机教程下载
  9. 安装Office Visio 提示Office 16 Click-to-Run Extensibility Component
  10. java 自定义标签_Java自定义标签用法实例分析