《算法导论的Java实现》 11 基本数据结构

chen09 2011-12-07 10:33:35
Blog地址
《算法导论的Java实现》 11 基本数据结构


11 基本数据结构

code前要说的话
每次都是code后会有感想,这次却是code前有话要说。
“数据结构”是大学计算机里一个72课时的主干课程,教科书里的伪代码基本类似Pascal,也有用C来实现的。
而我现在要用Java来实现却遇到一点小问题。
首先,Java的基本API里面,各种数据结构非常完备,如果我只是抄袭一遍,将没有任何意义。然而,由于已经浏览过那些API,所以实现《算法导论》的数据结构伪代码时,不受Java底层API的影响,是不可能的。
其次,如果是C,那么很多都是指针操作,我反而不用去考虑指针指向的那个区域是什么类型(一般是个struct)。而Java这种面向对象的语言,到了现在又支持泛型。
我以前的排序算法的Java实现里,尽量都支持了泛型。但是现在,考虑到很多的数据结构的存储都是用数组,数组加泛型,我尽量去做,但是会不会遇到问题?我实在没有把握。

11.1 栈和队列
伪代码:

STACK-EMPTY(S)
1 if top[S] = 0
2 then return TRUE
3 else return FALSE

PUSH(S, x)
1 top[S] ← top[S] + 1
2 S[top[S]] ← x

POP(S)
1 if STACK-EMPTY(S)
2 then error "underflow"
3 else top[S] ← top[S] - 1
4 return S[top[S] + 1]


Java代码:

import java.util.Arrays;
import java.util.EmptyStackException;

public class Stack<E> {
private int count;
private Object[] objs;
private int capacityIncrement;

private int top() {
return count;
}

private void ensureCapacityHelper(int minCapacity) {
int oldCapacity = objs.length;
if (minCapacity > oldCapacity) {
int newCapacity = (capacityIncrement > 0) ? (oldCapacity + capacityIncrement)
: (oldCapacity * 2);
if (newCapacity < minCapacity) {
newCapacity = minCapacity;
}
objs = Arrays.copyOf(objs, newCapacity);
}
}

public boolean isEmpty() {
return top() == 0;
}

public synchronized E push(E item) {
ensureCapacityHelper(count + 1);
objs[count++] = item;
return item;
}

@SuppressWarnings("unchecked")
public synchronized E pop() {
if (isEmpty())
throw new EmptyStackException();
else {
Object obj = (E) objs[count - 1];
count--;
objs[count] = null;
return (E) obj;
}
}

public Stack() {
this(10);
}

public Stack(int initialCapacity) {
this(initialCapacity, 0);
}

public Stack(int initialCapacity, int capacityIncrement) {
objs = new Object[initialCapacity];
}

public static void main(String[] args) {
Stack<Integer> stack = new Stack<Integer>();
for (int i = 0; i < 11; i++) {
stack.push(i);
}
while (!stack.isEmpty()) {
System.out.print(stack.pop() + " ");
}
}

}


输出:
10 9 8 7 6 5 4 3 2 1 0

code后感
用Java实现的时候,我以伪代码为基准,同时参照了java.util.Stack和java.util.Vector的源代码。
《算法导论》的原文里有一句“不考虑栈溢出的问题”,但是我的实现却不能不考虑。毕竟现在这些代码不仅仅是研究用的,大部分可以直接运用在实际项目中。
所以,ensureCapacityHelper这个函数被我原封不动的copy过来用。这个函数的作用就是,当栈上溢的时候,扩张栈的大小。类似的操作,在别的数据结构里还会出现。
在参考了Java底层的API之后,我们会发现:当栈上溢的时候,ensureCapacityHelper被调用,但是当pop被调用时,栈的大小不会被变小,虽然有这么一句“objs[count] = null;”,GC会释放栈元素占用的内存,但是栈本身占用的空间不会缩小。
所以在实际运用中,如果是使用Java的API的话,Stack一旦被用完,最好释放掉,不要重复利用。如果是自己动手实现Stack,最好在pop之后,有个timing,按照capacityIncrement,去减小数据区的大小。


伪代码:

ENQUEUE(Q, x)
1 Q[tail[Q]] ← x
2 if tail[Q] = length[Q]
3 then tail[Q] ← 1
4 else tail[Q] ← tail[Q] + 1

DEQUEUE(Q)
1 x ← Q[head[Q]]
2 if head[Q] = length[Q]
3 then head[Q] ← 1
4 else head[Q] ← head[Q] + 1
5 return x


Java代码:

import java.util.Arrays;
import java.util.NoSuchElementException;

public class Queue<E> {
private int head = 0;
private int tail = 0;
private Object[] objs;
private int capacityIncrement;

public boolean isEmpty() {
return head == tail;
}

public synchronized void enqueue(E item) {
objs[tail] = item;
if (tail == objs.length - 1)
tail = 0;
else
tail++;
if (tail == head) {
int oldLength = objs.length;
ensureCapacityHelper(objs.length + 1);
for (int i = tail; i < oldLength; i++) {
objs[i + objs.length - oldLength] = objs[i];
}
head += objs.length - oldLength;
}
}

@SuppressWarnings("unchecked")
public synchronized E dequeue() {
if (isEmpty())
throw new NoSuchElementException();
Object obj = objs[head];
if (head == objs.length - 1)
head = 0;
else
head++;
return (E) obj;
}

private void ensureCapacityHelper(int minCapacity) {
int oldCapacity = objs.length;
if (minCapacity > oldCapacity) {
int newCapacity = (capacityIncrement > 0) ? (oldCapacity + capacityIncrement)
: (oldCapacity * 2);
if (newCapacity < minCapacity) {
newCapacity = minCapacity;
}
objs = Arrays.copyOf(objs, newCapacity);
}
}

public Queue() {
this(10);
}

public Queue(int initialCapacity) {
this(initialCapacity, 0);
}

public Queue(int initialCapacity, int capacityIncrement) {
objs = new Object[initialCapacity];
}

public static void main(String[] args) {
Queue<Integer> queue = new Queue<Integer>();
for (int i = 0; i < 8; i++)
queue.enqueue(i);

for (int i = 0; i < 4; i++)
System.out.print(queue.dequeue() + " ");

for (int i = 0; i < 9; i++)
queue.enqueue(i + 10);

while (!queue.isEmpty())
System.out.print(queue.dequeue() + " ");

}

}


输出:
0 1 2 3 4 5 6 7 10 11 12 13 14 15 16 17 18


code后感
简短的伪代码的Java实现如此冗长,原因在于要考虑溢出。
入队时,如果溢出,我也使用了ensureCapacityHelper来扩张objs数组,并且调整指针head,以及移动相应的数组内容。
出队和栈的pop一样,如果objs数组被扩张过,也不会恢复。所以,也一样可以考虑在某个timing缩小objs数组。



11.2 链表

LIST-SEARCH(L, k)
1 x ← head[L]
2 while x ≠ NIL and key[x] ≠ k
3 do x ← next[x]
4 return x

LIST-INSERT(L, x)
1 next[x] ← head[L]
2 if head[L] ≠ NIL
3 then prev[head[L]] ← x
4 head[L] ← x
5 prev[x] ← NIL

LIST-DELETE(L, x)
1 if prev[x] ≠ NIL
2 then next[prev[x]] ← next[x]
3 else head[L] ← next[x]
4 if next[x] ≠ NIL
5 then prev[next[x]] ← prev[x]


Java代码:

public class List<E> {

private transient Entry<E> header = new Entry<E>(null);

public static class Entry<E> {
E element;
Entry<E> next;
Entry<E> previous;

Entry(E element) {
this.element = element;
}
}

public Entry<E> search(E x) {
if (x == null)
return null;
Entry<E> entry = header;
while (entry != null && !x.equals(entry.element))
entry = entry.next;
return entry;
}

public Entry<E> insert(E x) {
Entry<E> newEntry = new Entry<E>(x);
newEntry.next = header;
if (header != null)
header.previous = newEntry;
header = newEntry;
newEntry.previous = null;
return newEntry;
}

public void delete(E x) {
Entry<E> entry = search(x);
if (entry.previous != null)
entry.previous.next = entry.next;
else
header = entry.next;
if (entry.next != null)
entry.next.previous = entry.previous;
}

public static void main(String[] args) {
List<Integer> ll = new List<Integer>();
ll.insert(1);
ll.insert(2);
ll.insert(3);
ll.insert(4);
ll.delete(3);
Entry<Integer> e = ll.search(2);
System.out.println(e.next.element);
System.out.println(e.previous.element);
}

}


输出:
1
4

code后感
我仿照了LinkedList的代码,定义了内部类Entry。因为Java没有指针,所以在一个实体上加类Entry类型的next和previous,来指向前一个实体和后一个实体。


哨兵(Sentinels)

LIST-DELET′ (L, x)
1 next[prev[x]] ← next[x]
2 prev[next[x]] ← prev[x]

LIST-SEARC′(L, k)
1 x ← next[nil[L]]
2 while x ≠ nil[L] and key[x] ≠ k
3 do x ← next[x]
4 return x

LIST-INSER′ (L, x)
1 next[x] ← next[nil[L]]
2 prev[next[nil[L]]] ← x
3 next[nil[L]] ← x
4 prev[x] ← nil[L]


Java代码:
忽略

code后感
我忽略了哨兵的链表的Java实现,却要写code后感,看上去有点滑稽。
实际上,前面非哨兵的链表Java程序里,header这个Entry在伪代码里是个函数,它恰好就可以充当哨兵nil[L],所以只要稍微改写一下前面的代码,就可以把一个双向链表变成一个双向环链表。除非后面的应用有需要环链表,否则我不打算实现这段伪代码了。


...全文
181 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
xiongyu2006 2011-12-07
  • 打赏
  • 举报
回复
嗯,楼主的博客不错,看看还是有收获的。学习
市面上能下载的《算法导论》中文版都没有目录(标签),阅读极不方便,翻阅困难。本人(crocostone)亲自手动制作了完整的标签,包括章、节、小节的标签,在Acrobat 7.0和9.0版本和FoxitReader 4.2版本均能打开。 而且,我精心调整了文档的大小,打开或点击标签的时候,默认就是最适合阅读、眼睛最舒服的文档大小,无需再调整大小。 本人亲自制作,在CSDN上奉献,欢迎使用!有了目录(标签),学习效率真的可以提高一大截啊!!!注意本压缩包使用WinRAR分卷压缩,4个部分都下载后才能解压! 为什么要分卷:整个文件有130MB,crocostone的上传权限不够,所以只能分卷压缩。已经测试:这4个压缩包,使用WinRAR/7zip/Haozip都能正确解压!!! 内容: 1、全世界唯一带“完整”目录的《算法导论》第二版中文版。 2、目前能找到的多个版本的习题答案和代码,有Java实现的,C++实现的,官方的、非官方的,教参,考试题答案等等! 3、讲义。 书籍介绍: 《算法导论》(Introduction to Algorithms)原书第二版,Thomas H. Cormen(科曼)、Charles E. Leiserson、Ronald L.Rivest、Clifford Stein著,南京大学潘金贵、顾铁成、李成法、叶懋等译,机械工业出版社,2006。本书简称CLRS,麻省理工学院教材,全世界最广泛使用的算法超经典书籍,学习编程必看之书。作者之一的Rivest就是RSA算法发明者的R,2002年图灵奖得主。算法是程序员必练内功。此书主要讨论算法,数据结构方面的内容稍少。中文翻译质量不错。 ########################【对于crocostone本人前面发的算法导论的资源的说明】########################### download.csdn.net/source/3109111和download.csdn.net/source/3109150是一套两个部分的压缩文件,后缀名是001和002,不要改名,只能用7zip和Haozip解压,用WinRAR无法解压,解压后是带章、节、小节目录的算法导论。 download.csdn.net/source/3108513和download.csdn.net/source/3108520是另一套两个部分的压缩文件,后缀名是001和002,不要改名,只能用7zip和Haozip解压,用WinRAR无法解压,解压后是带章目录的算法导论,但是没有节和小节的目录。 本人的电脑以前没有WinRAR,而是一直使用7zip,但是7zip制作的zip分卷压缩格式竟然与WinRAR不兼容,导致前面发的资源,用WinRAR的网友说无法解压,在这里表示抱歉!使用7zip或Haozip的人都解压成功了。 这次发的资源,4个压缩包,使用WinRAR/7zip/Haozip都能正确解压! 请CSDN网友,下载完,评论的同时,要点击评论框上方的五角星(共5个五角星),这样你的被扣的积分就可以返还,还会加一分。如果只评论,不点击小五角星,积分不会返还。一定要先下载完,再评论。如果先评论后下载,或者在下载的过程中评论,积分同样不会返还。 数据结构教材,我强烈推荐Sartaj Sahni著《数据结构算法与应用——C++语言描述》。这是一部难得的好书,作者循序渐进,娓娓道来,每一种数据结构和算法都给出了详细的实现代码和运行结果,而且代码质量极高,甚至可以直接照搬到商业软件开发中。此书的算法部分也很精到,比算法导论更容易学习和入门。Sartaj Sahni《数据结构算法与应用——C++语言描述》全集,包含中英文图书、代码、习题答案、演示动画,都是我亲自从此书的官方网站下载并汇总的,绝对权威,请在这里下载:download.csdn.net/source/3043982 算法和数据结构是计算机的绝对核心技术。学好核心技术,既为了自己,也为了天空不落下别国的炸弹!!!
市面上能下载的《算法导论》中文版都没有目录(标签),阅读极不方便,翻阅困难。本人(crocostone)亲自手动制作了完整的标签,包括章、节、小节的标签,在Acrobat 7.0和9.0版本和FoxitReader 4.2版本均能打开。 而且,我精心调整了文档的大小,打开或点击标签的时候,默认就是最适合阅读、眼睛最舒服的文档大小,无需再调整大小。 本人亲自制作,在CSDN上奉献,欢迎使用!有了目录(标签),真的可以提高不少的学习效率啊! 注意本压缩包有两个部分,此为第1部分。两个部分都下载后才能解压! (注:本人昨天发了一个类似的资源,但是只包含章的标签。本资源包含章、节和所有小节的标签,阅读更方便!) 书籍介绍: 《算法导论》(Introduction to Algorithms)第二版,Thomas H. Cormen、Charles E. Leiserson、Ronald L.Rivest、Clifford Stein著,南京大学潘金贵、顾铁成、李成法、叶懋译,机械工业出版社,2006。本书简称CLRS,麻省理工学院教材,全世界最广泛使用的算法超经典书籍,学习编程必看之书。作者之一的Rivest就是RSA算法发明者的R,2002年图灵奖得主。此书主要讨论算法,数据结构方面的内容稍少。中文翻译质量不错。 ########################【对于crocostone本人前面发的算法导论的资源的说明】########################### download.csdn.net/source/3109111和download.csdn.net/source/3109150是一套两个部分的压缩文件,后缀名是001和002,不要改名,只能用7zip和Haozip解压,用WinRAR无法解压,解压后是带章、节、小节目录的算法导论。 download.csdn.net/source/3108513和download.csdn.net/source/3108520是另一套两个部分的压缩文件,后缀名是001和002,不要改名,只能用7zip和Haozip解压,用WinRAR无法解压,解压后是带章目录的算法导论,但是没有节和小节的目录。 本人的电脑以前没有WinRAR,而是一直使用7zip,但是7zip制作的zip分卷压缩格式竟然与WinRAR不兼容,导致前面发的资源,用WinRAR的网友说无法解压,在这里表示抱歉!使用7zip或Haozip的人都解压成功了。 请CSDN网友,下载完,评论的同时,要点击评论框上方的五角星(共5个五角星),这样你的被扣的积分就可以返还,还会加一分。如果只评论,不点击小五角星,积分不会返还。一定要先下载完,再评论。如果先评论后下载,或者在下载的过程中评论,积分同样不会返还。 数据结构和算法书籍,我强烈推荐Sartaj Sahni(萨尔塔·萨尼)著《数据结构算法与应用——C++语言描述》。这是一部难得的好书,作者Sartaj Sahni也是国际知名的算法大师,循序渐进,娓娓道来,每一种数据结构和算法都给出了详细的实现代码和运行结果,而且代码质量极高,甚至可以直接照搬到商业软件开发中。数据结构部分详尽全面,只看此一本即可完全学会。算法部分也很精要,比算法导论更容易学习和入门。Sartaj Sahni《数据结构算法与应用——C++语言描述、Java语言描述》全集,包含中英文图书、代码、习题答案、演示动画、考试题,都是我亲自从此书的官方网站下载并汇总的,绝对权威,请在这里下载:download.csdn.net/source/3043982。 算法和数据结构是计算机的绝对核心技术。学好核心技术,既为了自己,也为了天空不落下别国的炸弹!!! 另外: 如果觉得贵,可以下载《算法导论》全集,包含中英文图书、C++/Java代码、讲义、习题答案等,包含了本资源,而且可以用WinRAR解压,下载地址: http://download.csdn.net/source/3124028 http://download.csdn.net/source/3124222 http://download.csdn.net/source/3124740 http://download.csdn.net/source/3124760
程序 = 数据结构 + 算法  程序是为了解决实际问题而存在的。然而为了解决问题,必定会使用到某些数据结构以及设计一个解决这种数据结构的算法。如果说各种编程语言是程序员的招式,那么数据结构和算法就相当于程序员的内功。编程实战算法,不是念PPT,我们讲的就是实战与代码实现与企业应用。程序 = 数据结构 + 算法                ——图灵奖得主,计算机科学家N.Wirth(沃斯)作为程序员,我们做机器学习也好,做python开发也好,java开发也好。有一种对所有程序员无一例外的刚需 —— 算法与数据结构日常增删改查 + 粘贴复制 + 搜索引擎可以实现很多东西。同样,这样也是没有任何竞争力的。我们只可以粘贴复制相似度极高的功能,稍复杂的逻辑没有任何办法。语言有很多,开发框架更是日新月异3个月不学就落后我们可以学习很多语言,很多框架,但招聘不会考你用5种语言10种框架实现同一个功能。真正让程序员有区分度,企业招聘万年不变的重点 —— 算法与数据结构。算法代表程序员水平的珠穆朗玛。如果说各种编程语言是程序员的招式,那么数据结构和算法就相当于程序员的内功。 想写出精炼、优秀的代码,不通过不断的锤炼,是很难做到的。 开这个系列的目的是为了自我不断积累。不积跬步无以至千里嘛。
市面上能下载的《算法导论》中文版都没有目录(标签),阅读极不方便,翻阅困难。本人(crocostone)亲自手动制作了完整的标签,包括章、节、小节的标签,在Acrobat 7.0和9.0版本和FoxitReader 4.2版本均能打开。 而且,我精心调整了文档的大小,打开或点击标签的时候,默认就是最适合阅读、眼睛最舒服的文档大小,一般无需再调整大小。 本人亲自制作,在CSDN上奉献,欢迎使用!有了目录(标签),真的可以提高不少的学习效率啊! 注意本压缩包有两个部分,此为第2部分。两个部分都下载后才能解压! (注:本人前面发了一个类似的资源,但是由于制作匆忙,只包含章的标签。本资源包含章、节和所有小节的标签,更方便!) 书籍介绍: 《算法导论》(Introduction to Algorithms)第二版,Thomas H. Cormen、Charles E. Leiserson、Ronald L.Rivest、Clifford Stein著,南京大学潘金贵、顾铁成、李成法、叶懋译,机械工业出版社,2006。本书简称CLRS,麻省理工学院教材,全世界最广泛使用的算法超经典书籍,学习编程必看之书。作者之一的Rivest就是RSA算法发明者的R,2002年图灵奖得主。此书主要讨论算法,数据结构方面的内容稍少。中文翻译质量不错。 ########################【对于crocostone本人前面发的算法导论的资源的说明】########################### download.csdn.net/source/3109111和download.csdn.net/source/3109150是一套两个部分的压缩文件,后缀名是001和002,不要改名,只能用7zip和Haozip解压,用WinRAR无法解压,解压后是带章、节、小节目录的算法导论。 download.csdn.net/source/3108513和download.csdn.net/source/3108520是另一套两个部分的压缩文件,后缀名是001和002,不要改名,只能用7zip和Haozip解压,用WinRAR无法解压,解压后是带章目录的算法导论,但是没有节和小节的目录。 本人的电脑以前没有WinRAR,而是一直使用7zip,但是7zip制作的zip分卷压缩格式竟然与WinRAR不兼容,导致前面发的资源,用WinRAR的网友说无法解压,在这里表示抱歉!使用7zip或Haozip的人都解压成功了。 请CSDN网友,下载完,评论的同时,要点击评论框上方的五角星(共5个五角星),这样你的被扣的积分就可以返还,还会加一分。如果只评论,不点击小五角星,积分不会返还。一定要先下载完,再评论。如果先评论后下载,或者在下载的过程中评论,积分同样不会返还。 数据结构和算法书籍,我强烈推荐Sartaj Sahni(萨尔塔·萨尼)著《数据结构算法与应用——C++语言描述》。这是一部难得的好书,作者Sartaj Sahni也是国际知名的算法大师,循序渐进,娓娓道来,每一种数据结构和算法都给出了详细的实现代码和运行结果,而且代码质量极高,甚至可以直接照搬到商业软件开发中。数据结构部分详尽全面,只看此一本即可完全学会。算法部分也很精要,比算法导论更容易学习和入门。Sartaj Sahni《数据结构算法与应用——C++语言描述、Java语言描述》全集,包含中英文图书、代码、习题答案、演示动画、考试题,都是我亲自从此书的官方网站下载并汇总的,绝对权威,请在这里下载:download.csdn.net/source/3043982。 算法和数据结构是计算机的绝对核心技术。学好核心技术,既为了自己,也为了天空不落下别国的炸弹!!! 另外: 如果觉得贵,可以下载《算法导论》全集,包含中英文图书、C++/Java代码、讲义、习题答案等,包含了本资源,而且可以用WinRAR解压,下载地址: http://download.csdn.net/source/3124028 http://download.csdn.net/source/3124222 http://download.csdn.net/source/3124740 http://download.csdn.net/source/3124760

62,615

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧