HashMap在JDK1.8為什么改用使用尾插法
因為 1.7頭插法擴容時,頭插法會使鏈表發生反轉,多線程環境下會產生環;
A 線程在插入節點 B,B 線程也在插入,遇到容量不夠開始擴容,重新 hash,放置元素,采用頭插法,后遍歷到的 B 節點放入了頭部,這樣形成了環。
1、假設容器大小為2,數組0 的鏈表上初始有個 A節點。A線程和B線程同時插入B節點。
2、B線程cup占用、頭指針指向A節點后 cup被A線程占用。
3、A線程插入節點B時,剛好hash 到數組0,則該鏈表 為 B —> A。
4、B線程 插入節點B時,發現內存不夠,進行resize擴容操作,恰巧節點rehash后也是在同一個位置上。該方法實現的機制就是將每個鏈表轉化到新鏈表,並且鏈表中的位置發生反轉(鏈表轉置)。現在為 A —> B。

5、B實現插入節點B操作后就形成了環。

以上參考自:https://blog.csdn.net/weixin_42373997/article/details/112085344?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_baidulandingword-0&spm=1001.2101.3001.4242、https://blog.csdn.net/csdn_1107/article/details/108236495
以下轉載自:https://blog.csdn.net/qq_40938077/article/details/80216563
方法1:頭插法
基本思路:
定義一個鏈表類型的指針l,指針l指向的是鏈表的首地址,而不是鏈表的第一個數,指針l指向的下一個鏈表類型才是鏈表的第一個數,每次往鏈表中加數都加到鏈表中的第1個位置(即指針l指向的位置)。

代碼:
最好自己看代碼在紙上模擬一下過程
#include<bits/stdc++.h> using namespace std typedef struct Node { int value; struct Node *next; }node,*linkedlist; linkedlist linkedlistcreath()//返回的是該鏈表的地址 { node *l=(node*)malloc(sizeof(node)); l->next=NULL; int number; while (scanf("%d",&number)!=EOF) { node *p=(node*)malloc(sizeof(node));//新建一個node結構並為其申請空間 p->value=number;//給新建的node結構賦值 p->next=l->next;//賦值p所指的節點(就是l所指的節點,即鏈表的第2個節點) l->next=p;//將l所指的節點更新為p點 } return l;//返回頭節點地址 }

方法2:尾插法
基本思路:
還是先定義一個鏈表類型的指針l,指針l指向的是鏈表的首地址,而不是鏈表的第一個數,指針l指向的下一個鏈表類型才是鏈表的第一個數,然后定義一個r指針,保證r指針始終指向鏈表的最后一個位置上的節點,然后讓新加的節點加入到r指針指向的節點的后面。

代碼如下:
最好自己看代碼在紙上模擬一下過程
#include<bits/stdc++.h> using namespace std; typedef struct Node { int value; struct Node *next; } node,*linkedlist; linkedlist linkedlistcreatt()//返回的是該鏈表的地址 { node *l=(node*)malloc(sizeof(node)); l->next=NULL; node *r;//r指向的始終是該鏈表的最后一個node結構 r=l;//這個地方是地址之間的賦值,所以對r操作就相當於對l操作,即對鏈表最后一個node結構操作 int number; while (scanf("%d",&number)!=EOF) { node *p=(node*)malloc(sizeof(node));//新建一個node結構並為其申請空間 p->value=number;//給新建的node結構賦值 r->next=p;//將p插入到鏈表的最后一個node結構的后面 p->next=NULL;//此時p已經是鏈表的最后一個了,給p的next賦值 r=p;//讓r等於鏈表的最后一個node結構,即p節點 } return l;//返回頭節點的地址 }

轉載:https://blog.csdn.net/qq_40938077/article/details/80216563
