Java 單鏈表數(shù)據(jù)結(jié)構(gòu)的增刪改查教程
我就廢話不多說了,大家還是直接看代碼吧~
package 鏈表;
/**
*
*1)單鏈表的插入、刪除、查找操作;
* 2)鏈表中存儲的是int類型的數(shù)據(jù);
**/
public class SinglyLinkedList {
private Node head = null;
//查找操作
public Node findByValue(int value){
Node p = head; //從鏈表頭部開始查找
while(p.next != null && p.data != value){//如果數(shù)據(jù)不相等并且下一個節(jié)點不為null,繼續(xù)查找
p = p.next;
}
return p;
}
//通過index查找
public Node findByIndex(int index){
Node p = head; //從鏈表頭部開始查找
int count = 0; //指針計數(shù)器
while(p.next != null && index != count){ //當(dāng)下個節(jié)點不為null,并且計數(shù)器不等于index的時候繼續(xù)查找
p = p.next;
count++;
}
return p;
}
//無頭部節(jié)點(哨兵),表頭部插入一個值,這種操作和輸入的順序相反,逆序
public void insertToHead(int value){
Node newNode = new Node(value,null);
insertToHead(newNode);
}
//無頭部節(jié)點(哨兵),表頭部插入新節(jié)點,這種操作和輸入的順序相反,逆序
public void insertToHead(Node newNode){
if(head == null){
head = newNode;
}else{
newNode.next = head;
head = newNode;
}
}
//鏈表尾部插入,按順序插入,時間復(fù)雜度平均為O(n),這個可以優(yōu)化,定義多一個尾部節(jié)點,不存儲任何數(shù)據(jù),時間復(fù)雜度未O(1)
public void insertTail(int value){
Node newNode = new Node(value,null);
if(head == null){//鏈表為空
head = newNode;
}else{//直接從鏈表頭開始找,知道找到鏈尾節(jié)點
Node curr = head;
while(curr.next != null){
curr = curr.next;
}
curr.next = newNode;
}
}
//在指定節(jié)點后面插入新節(jié)點,直接在這個節(jié)點后面斷開連接,直接插入
public void insertAfter(Node p,int value){
Node newNode = new Node(value,null);
insertAfter(p,newNode);
}
//在指定節(jié)點后面插入新節(jié)點,直接在這個節(jié)點后面斷開連接,直接插入
public void insertAfter(Node p,Node newNode){
if(p == null){
return;
}
newNode.next = p.next;
p.next = newNode;
}
//在指定節(jié)點前面插入新節(jié)點
public void insertBefore(Node p,int value){
Node newNode = new Node(value,null);
insertBefore(p,newNode);
}
//在指定節(jié)點前面插入新節(jié)點
public void insertBefore(Node p,Node newNode){
if(p == null){
return;
}
if(p == head){//如果指定節(jié)點是頭節(jié)點
insertToHead(p);
return;
}
Node curr = head;//當(dāng)前節(jié)點,(查找指定節(jié)點p的前一個節(jié)點,當(dāng)curr的下個節(jié)點等于指定節(jié)點時候,curr就是指定節(jié)點的前一個節(jié)點
while(curr != null && curr.next != p){//當(dāng)前節(jié)點不為null,當(dāng)前節(jié)點的下個節(jié)點不等于指點節(jié)點,則繼續(xù)查找
curr = curr.next;
}
if(curr == null){//未找到指定節(jié)點p
return;
}
newNode.next = p;
curr.next = newNode;
}
//刪除指定節(jié)點
public void deleteByNode(Node p){
if(p == null || p == head){
return;
}
Node curr = head;//從鏈頭開始查找,curr是當(dāng)前節(jié)點,查找指定節(jié)點p的前一個節(jié)點,當(dāng)curr的下個節(jié)點等于指定節(jié)點時候,curr就是指定節(jié)點的前一個節(jié)點
while(curr != null && curr.next != p){//當(dāng)前節(jié)點不為null并且,下個節(jié)點不等于指定節(jié)點時候繼續(xù)查找
curr = curr.next;
}
if(curr == null){//未找到指定節(jié)點
return;
}
curr.next = curr.next.next;
}
//刪除指定值
public void deleteByValue(int value){
if(head == null){
return;
}
Node curr = head;//當(dāng)前節(jié)點,從鏈表頭開始查找
Node pre = null;//當(dāng)前節(jié)點的前一個節(jié)點,找查找指定的過程,要不斷地保存當(dāng)前節(jié)點的前一個節(jié)點
while(curr != null && curr.data != value){
pre = curr;
curr = curr.next;
}
if(curr == null){//未找到指定的值
return ;
}
if(pre == null){//鏈表頭數(shù)據(jù)就是指定的值
head = head.next;
}else{
pre.next = pre.next.next;//或者pre.next = curr.next;
}
}
//打印鏈表
public void printAll() {
Node curr = head;
while(curr != null){
System.out.println(curr.data);
curr = curr.next;
}
}
//單鏈表數(shù)據(jù)結(jié)構(gòu)類,以存儲int類型數(shù)據(jù)為例
public class Node{
private int data;
private Node next;
public Node(int data, Node next) {
this.data = data;
this.next = next;
}
public int getData(){
return data;
}
}
public static void main(String[]args) {
老師代碼.linkedlist06.SinglyLinkedList link = new 老師代碼.linkedlist06.SinglyLinkedList();
System.out.println("hello");
int data[] = {1, 2, 5, 3, 1};
for (int i = 0; i < data.length; i++) {
//link.insertToHead(data[i]);
link.insertTail(data[i]);
}
System.out.println("打印原始:");
link.printAll();
}
}
補充知識:Hbase+Spring Aop 配置Hbase鏈接的開啟和關(guān)閉
Spring 提供了HbaseTemplate 對Hbase數(shù)據(jù)庫的常規(guī)操作進行了簡單的封裝。
get,find方法分別對應(yīng)了單行數(shù)據(jù)查詢和list查詢。
這些查詢都要開啟和關(guān)閉Hbase數(shù)據(jù)庫鏈接
@Override
public <T> T execute(String tableName, TableCallback<T> action) {
Assert.notNull(action, "Callback object must not be null");
Assert.notNull(tableName, "No table specified");
HTableInterface table = getTable(tableName);
try {
boolean previousFlushSetting = applyFlushSetting(table);
T result = action.doInTable(table);
flushIfNecessary(table, previousFlushSetting);
return result;
} catch (Throwable th) {
if (th instanceof Error) {
throw ((Error) th);
}
if (th instanceof RuntimeException) {
throw ((RuntimeException) th);
}
throw convertHbaseAccessException((Exception) th);
} finally {
releaseTable(tableName, table);
}
}
private HTableInterface getTable(String tableName) {
return HbaseUtils.getHTable(tableName, getConfiguration(), getCharset(), getTableFactory());
}
private void releaseTable(String tableName, HTableInterface table) {
HbaseUtils.releaseTable(tableName, table, getTableFactory());
}
HTableInterface table = getTable(tableName); 獲取數(shù)據(jù)庫鏈接
releaseTable(tableName, table); 釋放鏈接
在HbaseUtils.getHTable:
if (HbaseSynchronizationManager.hasResource(tableName)) {
return (HTable) HbaseSynchronizationManager.getResource(tableName);
}
看見這個大家應(yīng)該都有是曾相似的感覺吧,這和Spring事務(wù)管理核心類TransactionSynchronizationManager很像,而實現(xiàn)也基本一樣
都是通過ThreadLocal將鏈接保存到當(dāng)前線程中。
我們要做的就是要像Srping 事務(wù)配置一樣,在進入service方法時通過Aop機制將tableNames對應(yīng)的鏈接加入到線程中。
Spring提供了這個Aop方法攔截器 HbaseInterceptor:
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
Set<String> boundTables = new LinkedHashSet<String>();
for (String tableName : tableNames) {
if (!HbaseSynchronizationManager.hasResource(tableName)) {
boundTables.add(tableName);
HTableInterface table = HbaseUtils.getHTable(tableName, getConfiguration(), getCharset(), getTableFactory());
HbaseSynchronizationManager.bindResource(tableName, table);
}
}
try {
Object retVal = methodInvocation.proceed();
return retVal;
} catch (Exception ex) {
if (this.exceptionConversionEnabled) {
throw convertHBaseException(ex);
}
else {
throw ex;
}
} finally {
for (String tableName : boundTables) {
HTableInterface table = (HTableInterface) HbaseSynchronizationManager.unbindResourceIfPossible(tableName);
if (table != null) {
HbaseUtils.releaseTable(tableName, table);
}
else {
log.warn("Table [" + tableName + "] unbound from the thread by somebody else; cannot guarantee proper clean-up");
}
}
}
}
很明顯在
Object retVal = methodInvocation.proceed();
也就是我們的service方法執(zhí)行前去獲取Hbase鏈接并通過HbaseSynchronizationManager.bindResource(tableName, table);綁定到線程中。
finally中releaseTable。
Aop配置如下:
<!-- 自動掃描beans+注解功能注冊 --> <context:component-scan base-package="com.xxx.xxx" /> <!-- 根據(jù)配置文件生成hadoopConfiguration --> <hdp:configuration resources="classpath:/hbase-site.xml" /> <!-- hadoopConfiguration == hdp:configuration --> <!-- <hdp:hbase-configuration configuration-ref="hadoopConfiguration" /> --> <bean id="hbaseTemplate" class="org.springframework.data.hadoop.hbase.HbaseTemplate"> <!-- hadoopConfiguration == hdp:configuration --> <property name="configuration" ref="hadoopConfiguration" /> </bean> <bean id="hbaseInterceptor" class="org.springframework.data.hadoop.hbase.HbaseInterceptor"> <property name="configuration" ref="hadoopConfiguration" /> <property name="tableNames"> <list> <value>table_name1</value> <value>table_name2</value> </list> </property> </bean> <!-- 使用aop增強, 織入hbase數(shù)據(jù)庫鏈接的開啟和關(guān)閉 --> <aop:config> <aop:pointcut id="allManagerMethod" expression="execution(* com.xxx.xxx.*.service..*(..))" /> <aop:advisor advice-ref="hbaseInterceptor" pointcut-ref="allManagerMethod" /> </aop:config>
Hbase的數(shù)據(jù)庫表鏈接跟傳統(tǒng)數(shù)據(jù)庫不太一樣, 開啟鏈接必需要表名, 所以HbaseInterceptor中必需設(shè)置private String[] tableNames;
在進入servcie方法時,tableNames中對應(yīng)的表鏈接都會開啟。這必然會造成浪費,因為并不是每個service都會把表都查詢一遍。
以上這篇Java 單鏈表數(shù)據(jù)結(jié)構(gòu)的增刪改查教程就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解java如何實現(xiàn)帶RequestBody傳Json參數(shù)的GET請求
在調(diào)試Fate平臺時,遇到了一個奇葩的接口類型,該接口為Get方式,入?yún)⑹且粋€json類型在body中傳遞,使用body中傳參的話為什么不用POST請求而使用了GET請求,下面我們就來深入研究一下2024-02-02
Java 方法引用與ambda表達(dá)式的聯(lián)系
這篇文章主要介紹了Java 方法引用與ambda表達(dá)式的聯(lián)系,方法引用通過方法的名字來指向一個方法, 方法引用同樣是Java 8 引入的新特性,而且和Lambda表達(dá)式有著不小的聯(lián)系,它同樣可以根據(jù)上下文進行推導(dǎo),進而可以簡化代碼2022-06-06
詳解SpringBoot實現(xiàn)ApplicationEvent事件的監(jiān)聽與發(fā)布
這篇文章主要為大家詳細(xì)介紹了SpringBoot如何實現(xiàn)ApplicationEvent事件的監(jiān)聽與發(fā)布,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-03-03

