簡單介紹線性表以及如何實現(xiàn)雙鏈表
線性表是一種線性結(jié)構(gòu),它是具有相同類型的n(n≥0)個數(shù)據(jù)元素組成的有限序列。
一、數(shù)組
數(shù)組有上界和下界,數(shù)組的元素在上下界內(nèi)是連續(xù)的。
存儲10,20,30,40,50的數(shù)組的示意圖如下:
數(shù)組的特點:數(shù)據(jù)是連續(xù)的;隨機訪問速度快。
數(shù)組中稍微復雜一點的是多維數(shù)組和動態(tài)數(shù)組。對于C語言而言,多維數(shù)組本質(zhì)上也是通過一維數(shù)組實現(xiàn)的。至于動態(tài)數(shù)組,是指數(shù)組的容量能動態(tài)增長的數(shù)組;對于C語言而言,若要提供動態(tài)數(shù)組,需要手動實現(xiàn);而對于C++而言,STL提供了Vector;對于Java而言,Collection集合中提供了ArrayList和Vector。
二、單向鏈表
單向鏈表(單鏈表)是鏈表的一種,它由節(jié)點組成,每個節(jié)點都包含下一個節(jié)點的指針。
單鏈表的示意圖如下:
表頭為空,表頭的后繼節(jié)點是"節(jié)點10"(數(shù)據(jù)為10的節(jié)點),"節(jié)點10"的后繼節(jié)點是"節(jié)點20"(數(shù)據(jù)為10的節(jié)點),...
單鏈表刪除節(jié)點
刪除"節(jié)點30"
刪除之前:"節(jié)點20" 的后繼節(jié)點為"節(jié)點30",而"節(jié)點30" 的后繼節(jié)點為"節(jié)點40"。
刪除之后:"節(jié)點20" 的后繼節(jié)點為"節(jié)點40"。
單鏈表添加節(jié)點
在"節(jié)點10"與"節(jié)點20"之間添加"節(jié)點15"
添加之前:"節(jié)點10" 的后繼節(jié)點為"節(jié)點20"。
添加之后:"節(jié)點10" 的后繼節(jié)點為"節(jié)點15",而"節(jié)點15" 的后繼節(jié)點為"節(jié)點20"。
單鏈表的特點是:節(jié)點的鏈接方向是單向的;相對于數(shù)組來說,單鏈表的的隨機訪問速度較慢,但是單鏈表刪除/添加數(shù)據(jù)的效率很高。
三、雙向鏈表
雙向鏈表(雙鏈表)是鏈表的一種。和單鏈表一樣,雙鏈表也是由節(jié)點組成,它的每個數(shù)據(jù)結(jié)點中都有兩個指針,分別指向直接后繼和直接前驅(qū)。所以,從雙向鏈表中的任意一個結(jié)點開始,都可以很方便地訪問它的前驅(qū)結(jié)點和后繼結(jié)點。一般我們都構(gòu)造雙向循環(huán)鏈表。
雙鏈表的示意圖如下:
表頭為空,表頭的后繼節(jié)點為"節(jié)點10"(數(shù)據(jù)為10的節(jié)點);"節(jié)點10"的后繼節(jié)點是"節(jié)點20"(數(shù)據(jù)為10的節(jié)點),"節(jié)點20"的前繼節(jié)點是"節(jié)點10";"節(jié)點20"的后繼節(jié)點是"節(jié)點30","節(jié)點30"的前繼節(jié)點是"節(jié)點20";...;末尾節(jié)點的后繼節(jié)點是表頭。
雙鏈表刪除節(jié)點
刪除"節(jié)點30"
刪除之前:"節(jié)點20"的后繼節(jié)點為"節(jié)點30","節(jié)點30" 的前繼節(jié)點為"節(jié)點20"。"節(jié)點30"的后繼節(jié)點為"節(jié)點40","節(jié)點40" 的前繼節(jié)點為"節(jié)點30"。
刪除之后:"節(jié)點20"的后繼節(jié)點為"節(jié)點40","節(jié)點40" 的前繼節(jié)點為"節(jié)點20"。
雙鏈表添加節(jié)點
在"節(jié)點10"與"節(jié)點20"之間添加"節(jié)點15"
添加之前:"節(jié)點10"的后繼節(jié)點為"節(jié)點20","節(jié)點20" 的前繼節(jié)點為"節(jié)點10"。
添加之后:"節(jié)點10"的后繼節(jié)點為"節(jié)點15","節(jié)點15" 的前繼節(jié)點為"節(jié)點10"。"節(jié)點15"的后繼節(jié)點為"節(jié)點20","節(jié)點20" 的前繼節(jié)點為"節(jié)點15"。
下面介紹雙鏈表的實現(xiàn),分別介紹C/C++/Java三種實現(xiàn)。
1. C實現(xiàn)雙鏈表
實現(xiàn)代碼
雙向鏈表頭文件(double_link.h)
#ifndef _DOUBLE_LINK_H #define _DOUBLE_LINK_H // 新建“雙向鏈表”。成功,返回表頭;否則,返回NULL extern int create_dlink(); // 撤銷“雙向鏈表”。成功,返回0;否則,返回-1 extern int destroy_dlink(); // “雙向鏈表是否為空”。為空的話返回1;否則,返回0。 extern int dlink_is_empty(); // 返回“雙向鏈表的大小” extern int dlink_size(); // 獲取“雙向鏈表中第index位置的元素”。成功,返回節(jié)點指針;否則,返回NULL。 extern void* dlink_get(int index); // 獲取“雙向鏈表中第1個元素”。成功,返回節(jié)點指針;否則,返回NULL。 extern void* dlink_get_first(); // 獲取“雙向鏈表中最后1個元素”。成功,返回節(jié)點指針;否則,返回NULL。 extern void* dlink_get_last(); // 將“value”插入到index位置。成功,返回0;否則,返回-1。 extern int dlink_insert(int index, void *pval); // 將“value”插入到表頭位置。成功,返回0;否則,返回-1。 extern int dlink_insert_first(void *pval); // 將“value”插入到末尾位置。成功,返回0;否則,返回-1。 extern int dlink_append_last(void *pval); // 刪除“雙向鏈表中index位置的節(jié)點”。成功,返回0;否則,返回-1 extern int dlink_delete(int index); // 刪除第一個節(jié)點。成功,返回0;否則,返回-1 extern int dlink_delete_first(); // 刪除組后一個節(jié)點。成功,返回0;否則,返回-1 extern int dlink_delete_last(); #endif
雙向鏈表實現(xiàn)文件(double_link.c)
#include <stdio.h> #include <malloc.h> /** * C 語言實現(xiàn)的雙向鏈表,能存儲任意數(shù)據(jù)。 * * @author skywang * @date 2013/11/07 */ // 雙向鏈表節(jié)點 typedef struct tag_node { struct tag_node *prev; struct tag_node *next; void* p; }node; // 表頭。注意,表頭不存放元素值?。。? static node *phead=NULL; // 節(jié)點個數(shù)。 static int count=0; // 新建“節(jié)點”。成功,返回節(jié)點指針;否則,返回NULL。 static node* create_node(void *pval) { node *pnode=NULL; pnode = (node *)malloc(sizeof(node)); if (!pnode) { printf("create node error!\n"); return NULL; } // 默認的,pnode的前一節(jié)點和后一節(jié)點都指向它自身 pnode->prev = pnode->next = pnode; // 節(jié)點的值為pval pnode->p = pval; return pnode; } // 新建“雙向鏈表”。成功,返回0;否則,返回-1。 int create_dlink() { // 創(chuàng)建表頭 phead = create_node(NULL); if (!phead) return -1; // 設置“節(jié)點個數(shù)”為0 count = 0; return 0; } // “雙向鏈表是否為空” int dlink_is_empty() { return count == 0; } // 返回“雙向鏈表的大小” int dlink_size() { return count; } // 獲取“雙向鏈表中第index位置的節(jié)點” static node* get_node(int index) { if (index<0 || index>=count) { printf("%s failed! index out of bound!\n", __func__); return NULL; } // 正向查找 if (index <= (count/2)) { int i=0; node *pnode=phead->next; while ((i++) < index) pnode = pnode->next; return pnode; } // 反向查找 int j=0; int rindex = count - index - 1; node *rnode=phead->prev; while ((j++) < rindex) rnode = rnode->prev; return rnode; } // 獲取“第一個節(jié)點” static node* get_first_node() { return get_node(0); } // 獲取“最后一個節(jié)點” static node* get_last_node() { return get_node(count-1); } // 獲取“雙向鏈表中第index位置的元素”。成功,返回節(jié)點值;否則,返回-1。 void* dlink_get(int index) { node *pindex=get_node(index); if (!pindex) { printf("%s failed!\n", __func__); return NULL; } return pindex->p; } // 獲取“雙向鏈表中第1個元素的值” void* dlink_get_first() { return dlink_get(0); } // 獲取“雙向鏈表中最后1個元素的值” void* dlink_get_last() { return dlink_get(count-1); } // 將“pval”插入到index位置。成功,返回0;否則,返回-1。 int dlink_insert(int index, void* pval) { // 插入表頭 if (index==0) return dlink_insert_first(pval); // 獲取要插入的位置對應的節(jié)點 node *pindex=get_node(index); if (!pindex) return -1; // 創(chuàng)建“節(jié)點” node *pnode=create_node(pval); if (!pnode) return -1; pnode->prev = pindex->prev; pnode->next = pindex; pindex->prev->next = pnode; pindex->prev = pnode; // 節(jié)點個數(shù)+1 count++; return 0; } // 將“pval”插入到表頭位置 int dlink_insert_first(void *pval) { node *pnode=create_node(pval); if (!pnode) return -1; pnode->prev = phead; pnode->next = phead->next; phead->next->prev = pnode; phead->next = pnode; count++; return 0; } // 將“pval”插入到末尾位置 int dlink_append_last(void *pval) { node *pnode=create_node(pval); if (!pnode) return -1; pnode->next = phead; pnode->prev = phead->prev; phead->prev->next = pnode; phead->prev = pnode; count++; return 0; } // 刪除“雙向鏈表中index位置的節(jié)點”。成功,返回0;否則,返回-1。 int dlink_delete(int index) { node *pindex=get_node(index); if (!pindex) { printf("%s failed! the index in out of bound!\n", __func__); return -1; } pindex->next->prev = pindex->prev; pindex->prev->next = pindex->next; free(pindex); count--; return 0; } // 刪除第一個節(jié)點 int dlink_delete_first() { return dlink_delete(0); } // 刪除組后一個節(jié)點 int dlink_delete_last() { return dlink_delete(count-1); } // 撤銷“雙向鏈表”。成功,返回0;否則,返回-1。 int destroy_dlink() { if (!phead) { printf("%s failed! dlink is null!\n", __func__); return -1; } node *pnode=phead->next; node *ptmp=NULL; while(pnode != phead) { ptmp = pnode; pnode = pnode->next; free(ptmp); } free(phead); phead = NULL; count = 0; return 0; }
雙向鏈表測試程序(dlink_test.c)
#include <stdio.h> #include "double_link.h" /** * C 語言實現(xiàn)的雙向鏈表的測試程序。 * * (01) int_test() * 演示向雙向鏈表操作“int數(shù)據(jù)”。 * (02) string_test() * 演示向雙向鏈表操作“字符串數(shù)據(jù)”。 * (03) object_test() * 演示向雙向鏈表操作“對象”。 * * @author skywang * @date 2013/11/07 */ // 雙向鏈表操作int數(shù)據(jù) void int_test() { int iarr[4] = {10, 20, 30, 40}; printf("\n----%s----\n", __func__); create_dlink(); // 創(chuàng)建雙向鏈表 dlink_insert(0, &iarr[0]); // 向雙向鏈表的表頭插入數(shù)據(jù) dlink_insert(0, &iarr[1]); // 向雙向鏈表的表頭插入數(shù)據(jù) dlink_insert(0, &iarr[2]); // 向雙向鏈表的表頭插入數(shù)據(jù) printf("dlink_is_empty()=%d\n", dlink_is_empty()); // 雙向鏈表是否為空 printf("dlink_size()=%d\n", dlink_size()); // 雙向鏈表的大小 // 打印雙向鏈表中的全部數(shù)據(jù) int i; int *p; int sz = dlink_size(); for (i=0; i<sz; i++) { p = (int *)dlink_get(i); printf("dlink_get(%d)=%d\n", i, *p); } destroy_dlink(); } void string_test() { char* sarr[4] = {"ten", "twenty", "thirty", "forty"}; printf("\n----%s----\n", __func__); create_dlink(); // 創(chuàng)建雙向鏈表 dlink_insert(0, sarr[0]); // 向雙向鏈表的表頭插入數(shù)據(jù) dlink_insert(0, sarr[1]); // 向雙向鏈表的表頭插入數(shù)據(jù) dlink_insert(0, sarr[2]); // 向雙向鏈表的表頭插入數(shù)據(jù) printf("dlink_is_empty()=%d\n", dlink_is_empty()); // 雙向鏈表是否為空 printf("dlink_size()=%d\n", dlink_size()); // 雙向鏈表的大小 // 打印雙向鏈表中的全部數(shù)據(jù) int i; char *p; int sz = dlink_size(); for (i=0; i<sz; i++) { p = (char *)dlink_get(i); printf("dlink_get(%d)=%s\n", i, p); } destroy_dlink(); } typedef struct tag_stu { int id; char name[20]; }stu; static stu arr_stu[] = { {10, "sky"}, {20, "jody"}, {30, "vic"}, {40, "dan"}, }; #define ARR_STU_SIZE ( (sizeof(arr_stu)) / (sizeof(arr_stu[0])) ) void object_test() { printf("\n----%s----\n", __func__); create_dlink(); // 創(chuàng)建雙向鏈表 dlink_insert(0, &arr_stu[0]); // 向雙向鏈表的表頭插入數(shù)據(jù) dlink_insert(0, &arr_stu[1]); // 向雙向鏈表的表頭插入數(shù)據(jù) dlink_insert(0, &arr_stu[2]); // 向雙向鏈表的表頭插入數(shù)據(jù) printf("dlink_is_empty()=%d\n", dlink_is_empty()); // 雙向鏈表是否為空 printf("dlink_size()=%d\n", dlink_size()); // 雙向鏈表的大小 // 打印雙向鏈表中的全部數(shù)據(jù) int i; int sz = dlink_size(); stu *p; for (i=0; i<sz; i++) { p = (stu *)dlink_get(i); printf("dlink_get(%d)=[%d, %s]\n", i, p->id, p->name); } destroy_dlink(); } int main() { int_test(); // 演示向雙向鏈表操作“int數(shù)據(jù)”。 string_test(); // 演示向雙向鏈表操作“字符串數(shù)據(jù)”。 object_test(); // 演示向雙向鏈表操作“對象”。 return 0; }
運行結(jié)果
----int_test---- dlink_is_empty()=0 dlink_size()=3 dlink_get(0)=30 dlink_get(1)=20 dlink_get(2)=10 ----string_test---- dlink_is_empty()=0 dlink_size()=3 dlink_get(0)=thirty dlink_get(1)=twenty dlink_get(2)=ten ----object_test---- dlink_is_empty()=0 dlink_size()=3 dlink_get(0)=[30, vic] dlink_get(1)=[20, jody] dlink_get(2)=[10, sky]
2. C++實現(xiàn)雙鏈表
實現(xiàn)代碼
雙向鏈表文件(DoubleLink.h)
#ifndef DOUBLE_LINK_HXX #define DOUBLE_LINK_HXX #include <iostream> using namespace std; template<class T> struct DNode { public: T value; DNode *prev; DNode *next; public: DNode() { } DNode(T t, DNode *prev, DNode *next) { this->value = t; this->prev = prev; this->next = next; } }; template<class T> class DoubleLink { public: DoubleLink(); ~DoubleLink(); int size(); int is_empty(); T get(int index); T get_first(); T get_last(); int insert(int index, T t); int insert_first(T t); int append_last(T t); int del(int index); int delete_first(); int delete_last(); private: int count; DNode<T> *phead; private: DNode<T> *get_node(int index); }; template<class T> DoubleLink<T>::DoubleLink() : count(0) { // 創(chuàng)建“表頭”。注意:表頭沒有存儲數(shù)據(jù)! phead = new DNode<T>(); phead->prev = phead->next = phead; // 設置鏈表計數(shù)為0 //count = 0; } // 析構(gòu)函數(shù) template<class T> DoubleLink<T>::~DoubleLink() { // 刪除所有的節(jié)點 DNode<T>* ptmp; DNode<T>* pnode = phead->next; while (pnode != phead) { ptmp = pnode; pnode=pnode->next; delete ptmp; } // 刪除"表頭" delete phead; phead = NULL; } // 返回節(jié)點數(shù)目 template<class T> int DoubleLink<T>::size() { return count; } // 返回鏈表是否為空 template<class T> int DoubleLink<T>::is_empty() { return count==0; } // 獲取第index位置的節(jié)點 template<class T> DNode<T>* DoubleLink<T>::get_node(int index) { // 判斷參數(shù)有效性 if (index<0 || index>=count) { cout << "get node failed! the index in out of bound!" << endl; return NULL; } // 正向查找 if (index <= count/2) { int i=0; DNode<T>* pindex = phead->next; while (i++ < index) { pindex = pindex->next; } return pindex; } // 反向查找 int j=0; int rindex = count - index -1; DNode<T>* prindex = phead->prev; while (j++ < rindex) { prindex = prindex->prev; } return prindex; } // 獲取第index位置的節(jié)點的值 template<class T> T DoubleLink<T>::get(int index) { return get_node(index)->value; } // 獲取第1個節(jié)點的值 template<class T> T DoubleLink<T>::get_first() { return get_node(0)->value; } // 獲取最后一個節(jié)點的值 template<class T> T DoubleLink<T>::get_last() { return get_node(count-1)->value; } // 將節(jié)點插入到第index位置之前 template<class T> int DoubleLink<T>::insert(int index, T t) { if (index == 0) return insert_first(t); DNode<T>* pindex = get_node(index); DNode<T>* pnode = new DNode<T>(t, pindex->prev, pindex); pindex->prev->next = pnode; pindex->prev = pnode; count++; return 0; } // 將節(jié)點插入第一個節(jié)點處。 template<class T> int DoubleLink<T>::insert_first(T t) { DNode<T>* pnode = new DNode<T>(t, phead, phead->next); phead->next->prev = pnode; phead->next = pnode; count++; return 0; } // 將節(jié)點追加到鏈表的末尾 template<class T> int DoubleLink<T>::append_last(T t) { DNode<T>* pnode = new DNode<T>(t, phead->prev, phead); phead->prev->next = pnode; phead->prev = pnode; count++; return 0; } // 刪除index位置的節(jié)點 template<class T> int DoubleLink<T>::del(int index) { DNode<T>* pindex = get_node(index); pindex->next->prev = pindex->prev; pindex->prev->next = pindex->next; delete pindex; count--; return 0; } // 刪除第一個節(jié)點 template<class T> int DoubleLink<T>::delete_first() { return del(0); } // 刪除最后一個節(jié)點 template<class T> int DoubleLink<T>::delete_last() { return del(count-1); } #endif
雙向鏈表測試文件(DlinkTest.cpp)
#include <iostream> #include "DoubleLink.h" using namespace std; // 雙向鏈表操作int數(shù)據(jù) void int_test() { int iarr[4] = {10, 20, 30, 40}; cout << "\n----int_test----" << endl; // 創(chuàng)建雙向鏈表 DoubleLink<int>* pdlink = new DoubleLink<int>(); pdlink->insert(0, 20); // 將 20 插入到第一個位置 pdlink->append_last(10); // 將 10 追加到鏈表末尾 pdlink->insert_first(30); // 將 30 插入到第一個位置 // 雙向鏈表是否為空 cout << "is_empty()=" << pdlink->is_empty() <<endl; // 雙向鏈表的大小 cout << "size()=" << pdlink->size() <<endl; // 打印雙向鏈表中的全部數(shù)據(jù) int sz = pdlink->size(); for (int i=0; i<sz; i++) cout << "pdlink("<<i<<")=" << pdlink->get(i) <<endl; } void string_test() { string sarr[4] = {"ten", "twenty", "thirty", "forty"}; cout << "\n----string_test----" << endl; // 創(chuàng)建雙向鏈表 DoubleLink<string>* pdlink = new DoubleLink<string>(); pdlink->insert(0, sarr[1]); // 將 sarr中第2個元素 插入到第一個位置 pdlink->append_last(sarr[0]); // 將 sarr中第1個元素 追加到鏈表末尾 pdlink->insert_first(sarr[2]); // 將 sarr中第3個元素 插入到第一個位置 // 雙向鏈表是否為空 cout << "is_empty()=" << pdlink->is_empty() <<endl; // 雙向鏈表的大小 cout << "size()=" << pdlink->size() <<endl; // 打印雙向鏈表中的全部數(shù)據(jù) int sz = pdlink->size(); for (int i=0; i<sz; i++) cout << "pdlink("<<i<<")=" << pdlink->get(i) <<endl; } struct stu { int id; char name[20]; }; static stu arr_stu[] = { {10, "sky"}, {20, "jody"}, {30, "vic"}, {40, "dan"}, }; #define ARR_STU_SIZE ( (sizeof(arr_stu)) / (sizeof(arr_stu[0])) ) void object_test() { cout << "\n----object_test----" << endl; // 創(chuàng)建雙向鏈表 DoubleLink<stu>* pdlink = new DoubleLink<stu>(); pdlink->insert(0, arr_stu[1]); // 將 arr_stu中第2個元素 插入到第一個位置 pdlink->append_last(arr_stu[0]); // 將 arr_stu中第1個元素 追加到鏈表末尾 pdlink->insert_first(arr_stu[2]); // 將 arr_stu中第3個元素 插入到第一個位置 // 雙向鏈表是否為空 cout << "is_empty()=" << pdlink->is_empty() <<endl; // 雙向鏈表的大小 cout << "size()=" << pdlink->size() <<endl; // 打印雙向鏈表中的全部數(shù)據(jù) int sz = pdlink->size(); struct stu p; for (int i=0; i<sz; i++) { p = pdlink->get(i); cout << "pdlink("<<i<<")=[" << p.id << ", " << p.name <<"]" <<endl; } } int main() { int_test(); // 演示向雙向鏈表操作“int數(shù)據(jù)”。 string_test(); // 演示向雙向鏈表操作“字符串數(shù)據(jù)”。 object_test(); // 演示向雙向鏈表操作“對象”。 return 0; }
示例說明
在上面的示例中,我將雙向鏈表的"聲明"和"實現(xiàn)"都放在頭文件中。而編程規(guī)范告誡我們:將類的聲明和實現(xiàn)分離,在頭文件(.h文件或.hpp)中盡量只包含聲明,而在實現(xiàn)文件(.cpp文件)中負責實現(xiàn)!
那么為什么要這么做呢?這是因為,在雙向鏈表的實現(xiàn)中,采用了模板;而C++編譯器不支持對模板的分離式編譯!簡單點說,如果在DoubleLink.h中聲明,而在DoubleLink.cpp中進行實現(xiàn)的話;當我們在其他類中創(chuàng)建DoubleLink的對象時,會編譯出錯。具體原因,可以參考"為什么C++編譯器不能支持對模板的分離式編譯"。
運行結(jié)果
----int_test---- is_empty()=0 size()=3 pdlink(0)=30 pdlink(1)=20 pdlink(2)=10 ----string_test---- is_empty()=0 size()=3 pdlink(0)=thirty pdlink(1)=twenty pdlink(2)=ten ----object_test---- is_empty()=0 size()=3 pdlink(0)=[30, vic] pdlink(1)=[20, jody] pdlink(2)=[10, sky]
3. Java實現(xiàn)雙鏈表
實現(xiàn)代碼
雙鏈表類(DoubleLink.java)
/** * Java 實現(xiàn)的雙向鏈表。 * 注:java自帶的集合包中有實現(xiàn)雙向鏈表,路徑是:java.util.LinkedList * * @author skywang * @date 2013/11/07 */ public class DoubleLink<T> { // 表頭 private DNode<T> mHead; // 節(jié)點個數(shù) private int mCount; // 雙向鏈表“節(jié)點”對應的結(jié)構(gòu)體 private class DNode<T> { public DNode prev; public DNode next; public T value; public DNode(T value, DNode prev, DNode next) { this.value = value; this.prev = prev; this.next = next; } } // 構(gòu)造函數(shù) public DoubleLink() { // 創(chuàng)建“表頭”。注意:表頭沒有存儲數(shù)據(jù)! mHead = new DNode<T>(null, null, null); mHead.prev = mHead.next = mHead; // 初始化“節(jié)點個數(shù)”為0 mCount = 0; } // 返回節(jié)點數(shù)目 public int size() { return mCount; } // 返回鏈表是否為空 public boolean isEmpty() { return mCount==0; } // 獲取第index位置的節(jié)點 private DNode<T> getNode(int index) { if (index<0 || index>=mCount) throw new IndexOutOfBoundsException(); // 正向查找 if (index <= mCount/2) { DNode<T> node = mHead.next; for (int i=0; i<index; i++) node = node.next; return node; } // 反向查找 DNode<T> rnode = mHead.prev; int rindex = mCount - index -1; for (int j=0; j<rindex; j++) rnode = rnode.prev; return rnode; } // 獲取第index位置的節(jié)點的值 public T get(int index) { return getNode(index).value; } // 獲取第1個節(jié)點的值 public T getFirst() { return getNode(0).value; } // 獲取最后一個節(jié)點的值 public T getLast() { return getNode(mCount-1).value; } // 將節(jié)點插入到第index位置之前 public void insert(int index, T t) { if (index==0) { DNode<T> node = new DNode<T>(t, mHead, mHead.next); mHead.next.prev = node; mHead.next = node; mCount++; return ; } DNode<T> inode = getNode(index); DNode<T> tnode = new DNode<T>(t, inode.prev, inode); inode.prev.next = tnode; inode.next = tnode; mCount++; return ; } // 將節(jié)點插入第一個節(jié)點處。 public void insertFirst(T t) { insert(0, t); } // 將節(jié)點追加到鏈表的末尾 public void appendLast(T t) { DNode<T> node = new DNode<T>(t, mHead.prev, mHead); mHead.prev.next = node; mHead.prev = node; mCount++; } // 刪除index位置的節(jié)點 public void del(int index) { DNode<T> inode = getNode(index); inode.prev.next = inode.next; inode.next.prev = inode.prev; inode = null; mCount--; } // 刪除第一個節(jié)點 public void deleteFirst() { del(0); } // 刪除最后一個節(jié)點 public void deleteLast() { del(mCount-1); } }
測試程序(DlinkTest.java)
/** * Java 實現(xiàn)的雙向鏈表。 * 注:java自帶的集合包中有實現(xiàn)雙向鏈表,路徑是:java.util.LinkedList * * @author skywang * @date 2013/11/07 */ public class DlinkTest { // 雙向鏈表操作int數(shù)據(jù) private static void int_test() { int[] iarr = {10, 20, 30, 40}; System.out.println("\n----int_test----"); // 創(chuàng)建雙向鏈表 DoubleLink<Integer> dlink = new DoubleLink<Integer>(); dlink.insert(0, 20); // 將 20 插入到第一個位置 dlink.appendLast(10); // 將 10 追加到鏈表末尾 dlink.insertFirst(30); // 將 30 插入到第一個位置 // 雙向鏈表是否為空 System.out.printf("isEmpty()=%b\n", dlink.isEmpty()); // 雙向鏈表的大小 System.out.printf("size()=%d\n", dlink.size()); // 打印出全部的節(jié)點 for (int i=0; i<dlink.size(); i++) System.out.println("dlink("+i+")="+ dlink.get(i)); } private static void string_test() { String[] sarr = {"ten", "twenty", "thirty", "forty"}; System.out.println("\n----string_test----"); // 創(chuàng)建雙向鏈表 DoubleLink<String> dlink = new DoubleLink<String>(); dlink.insert(0, sarr[1]); // 將 sarr中第2個元素 插入到第一個位置 dlink.appendLast(sarr[0]); // 將 sarr中第1個元素 追加到鏈表末尾 dlink.insertFirst(sarr[2]); // 將 sarr中第3個元素 插入到第一個位置 // 雙向鏈表是否為空 System.out.printf("isEmpty()=%b\n", dlink.isEmpty()); // 雙向鏈表的大小 System.out.printf("size()=%d\n", dlink.size()); // 打印出全部的節(jié)點 for (int i=0; i<dlink.size(); i++) System.out.println("dlink("+i+")="+ dlink.get(i)); } // 內(nèi)部類 private static class Student { private int id; private String name; public Student(int id, String name) { this.id = id; this.name = name; } @Override public String toString() { return "["+id+", "+name+"]"; } } private static Student[] students = new Student[]{ new Student(10, "sky"), new Student(20, "jody"), new Student(30, "vic"), new Student(40, "dan"), }; private static void object_test() { System.out.println("\n----object_test----"); // 創(chuàng)建雙向鏈表 DoubleLink<Student> dlink = new DoubleLink<Student>(); dlink.insert(0, students[1]); // 將 students中第2個元素 插入到第一個位置 dlink.appendLast(students[0]); // 將 students中第1個元素 追加到鏈表末尾 dlink.insertFirst(students[2]); // 將 students中第3個元素 插入到第一個位置 // 雙向鏈表是否為空 System.out.printf("isEmpty()=%b\n", dlink.isEmpty()); // 雙向鏈表的大小 System.out.printf("size()=%d\n", dlink.size()); // 打印出全部的節(jié)點 for (int i=0; i<dlink.size(); i++) { System.out.println("dlink("+i+")="+ dlink.get(i)); } } public static void main(String[] args) { int_test(); // 演示向雙向鏈表操作“int數(shù)據(jù)”。 string_test(); // 演示向雙向鏈表操作“字符串數(shù)據(jù)”。 object_test(); // 演示向雙向鏈表操作“對象”。 } }
運行結(jié)果
----int_test---- isEmpty()=false size()=3 dlink(0)=30 dlink(1)=20 dlink(2)=10 ----string_test---- isEmpty()=false size()=3 dlink(0)=thirty dlink(1)=twenty dlink(2)=ten ----object_test---- isEmpty()=false size()=3 dlink(0)=[30, vic] dlink(1)=[20, jody] dlink(2)=[10, sky]
以上就是本文的全部內(nèi)容,希望大家能夠理解,對大家有所幫助。
相關(guān)文章
Java實現(xiàn)簡單的銀行管理系統(tǒng)的示例代碼
這篇文章主要介紹了如何利用Java實現(xiàn)簡單的銀行管理系統(tǒng),可以實現(xiàn)存款,取款,查詢等功能,文中的示例代碼講解詳細,感興趣的可以了解一下2022-09-09IDEA版使用Java操作Redis數(shù)據(jù)庫的方法
這篇文章主要介紹了IDEA版使用Java操作Redis數(shù)據(jù)庫的方法,首先需要下載jedis.jar包,然后再工程中設置具體操作步驟跟隨小編一起學習下吧2021-08-08Java中ArrayList和LinkedList之間的區(qū)別_動力節(jié)點Java學院整理
這篇文章主要為大家詳細介紹了Java中ArrayList和LinkedList之間的區(qū)別,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-05-05Java?Stream?流中?Collectors.toMap?的用法詳解
這篇文章主要介紹了Stream?流中?Collectors.toMap?的用法,Collectors.toMap()方法是把List轉(zhuǎn)Map的操作,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2024-01-01Struts1教程之ActionMapping_動力節(jié)點Java學院整理
這篇文章主要介紹了Struts1教程之ActionMapping,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-09-09