Skip to content

Commit 1577906

Browse files
committed
add README
1 parent b32b629 commit 1577906

File tree

4 files changed

+291
-9
lines changed

4 files changed

+291
-9
lines changed

README.md

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
# 数据结构与算法 :dizzy:
2-
## 线性表 :ox:
2+
## 线性表
33
顺序表是一种典型的线性结构,是最简单、最常用的数据结构。
44
在计算机中线性表可以采用两种方式来保存,一种是顺序存储结构,另一种是链式存储结构.
5-
65
- [顺序表结构](./src/dataStructure/orderList)
76
- [链表结构](./src/dataStructure/linkedList)
87

98
## 栈结构
9+
栈结构是一种线性结构,栈结构包括两类:
10+
- [顺序栈结构](./src/dataStructure/stack):即使用一组地址连续的内存单元依次保存栈中的数据。在程序中,可以定义一个指定大小的结构数组来作为栈,序号为0的元素就是栈底,再定义一个变量top保存栈顶的序号即可。
11+
- 链式栈结构:即使用链表形式保存栈中各元素的值。链表首部(head引用所指向元素)为栈顶,链表尾部(指向地址为null)为栈底。
12+
13+
栈结构是按照“后进先出”的原则处理节点数据的。在栈结构中,只有栈顶元素是可以访问的。一般栈结构的基本操作有两个:
14+
- 入栈(Push):将数据保存到栈顶的操作。进行入栈操作前,先修改栈顶引用,使其向上移一个元素,然后将数据保存到栈顶引用所指的位置。
15+
- 出栈(Pop):将栈顶的数据弹出的操作。先取出栈顶指针所指位置的数据,再通过 修改栈顶引用,使其指向栈中的下一个元素。
1016

1117
## 队列结构
1218

@@ -16,6 +22,6 @@
1622

1723
# 数据结构与算法 面试题(Java版) :sparkles:
1824

19-
- [单例模式的六种实现](src/review02)
20-
- [二位数组中的查找](src/review03)
21-
- [字符串替换空格](src/review04)
25+
- [单例模式的六种实现](./src/review02)
26+
- [二位数组中的查找](./src/review03)
27+
- [字符串替换空格](./src/review04)
Lines changed: 171 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,171 @@
1-
# 链表结构
1+
# 链表结构 :apple:
2+
3+
典型的链表结构,包括如下内容:
4+
5+
1. 数据部分,保存的是该结点的实际数据。
6+
- 地址部分,保存的是下一个结点的地址。
7+
链表结构就是由许多这种结点构成的。在进行链表操作时,首先需定义一个“头引用”变量(一般以head表示),该引用变量指向链表结构的第一个结点,第一个结点的地址部分又指向第二个结点......直到最后一个结点。最后一个结点不再指向其他结点,称为“表尾”,一般在表尾的地址部分放一个空地址null,链表到此结束。
8+
9+
链式存储是最常用的存储方式之一,它不仅可用来表示线性表,而且可用来表示各种非线性的数据结构。链表结构还可以细分为如下几类:
10+
1. 单链表:同上面的链式结构一样,每个结点只包含一个引用。
11+
- 双向链表:若每个结点包含两个引用,一个指向下一个结点,另一个指向上一个结点,这就是双向链表。
12+
- 单循环链表:在单链表中,将终端结点的引用域null改为指向表头结点或开始结点即可构成单循环链表。
13+
- 多重链的循环链表:如果表中结点链在多个环上,将构成多重链的循环链表。
14+
15+
## 准备数据
16+
准备在 链表操作中需要用到的变量及类。
17+
18+
class DATA{
19+
String key; // 结点的关键字
20+
String name;
21+
int age;
22+
}
23+
24+
/*
25+
* 定义链表结构
26+
* Chain-type storage structure
27+
*/
28+
class CLType{
29+
DATA nodeData = new DATA();
30+
CLType nextNode;
31+
}
32+
上述代码定义了链表数据元素的类DATA及链表的类CLType。结点的具体数据保存在一个类DATA中,而引用nextNode用来指向下一个结点。
33+
34+
其实可以认为该链表是一个班级学生的记录,和上面顺序表所完成的工作类似。
35+
## 追加结点
36+
追加结点即在链表末尾增加一个结点。表尾结点的地址部分原来保存的是空地址null,此时需要将其设置为新增加结点的地址(即原表尾结点指向新增结点),然后将新增结点的地址部分设置为空地址null,即新增节点成为表尾
37+
38+
由于一般情况下,链表只有一个头引用head,要在末尾添加结点就需要从头引用head开始逐个检查,直到找到最后一个结点(即表尾)。
39+
40+
CLType CLAddEnd(CLType head, DATA nodeData){
41+
CLType node,htemp;
42+
if((node=new CLType())==null){
43+
System.out.println("申请内存失败!\n");
44+
return null;
45+
}else{
46+
node.nodeData = nodeData; // 在新申请的结点中保存数据
47+
node.nextNode = null; // 设置结点引用为空,即为表尾
48+
if(head == null){ // 当head为空时,加入的新结点即为头引用
49+
head = node;
50+
return head;
51+
}
52+
htemp = head;
53+
while(htemp.nextNode != null){ // 查找链表的末尾
54+
htemp = htemp.nextNode;
55+
}
56+
htemp.nextNode = node; // 在链表的末尾插入该结点
57+
return head; // 返回指代整个链表的头引用
58+
}
59+
}
60+
在上述代码中,输入参数head为链表头引用,输入参数nodeData为结点保存的数据。程序中,使用new关键字申请保存结点数据的内存空间,如果分配内存成功,node中将保存指向该内存区域的引用。然后,将传入的nodeData保存到申请的内存区域,并设置该结点指向下一结点的引用值为null,最后将该结点链接到链表的末尾。
61+
## 插入头结点
62+
插入头结点即在链表的首部添加结点的过程。
63+
步骤如下:
64+
1. 分配内存空间,保存新增的结点。
65+
- 使新增结点指向头引用head所指向的结点。
66+
- 使头引用head指向新增结点。
67+
68+
CLType CLAddFirst(CLType head, DATA nodeData){
69+
CLType node;
70+
if((node = new CLType())==null){
71+
System.out.println("申请内存失败!\n");
72+
return null;
73+
}else{
74+
node.nodeData = nodeData; // 保存数据
75+
node.nextNode = head; // 新加入的头结点的nextNode指向头引用所指的结点
76+
head = node; // 头引用指向新节点
77+
return head;
78+
}
79+
}
80+
81+
## 查找结点
82+
通过关键字进行查询。
83+
84+
CLType CLFindNode(CLType head, String key){
85+
CLType htemp;
86+
htemp = head;
87+
while(htemp!=null){ // 循环遍历,寻找关键字匹配的结点
88+
if(htemp.nodeData.key.compareTo(key)==0){
89+
return htemp;
90+
}
91+
htemp = htemp.nextNode;
92+
}
93+
return null;
94+
}
95+
在上述代码中,输入参数head为链表的头引用,输入参数key是用来在链表中进行查找结点的关键字。程序中,首先从链表头引用开始,对结点进行逐个比较,直到查找到。找到关键字相同的结点后,返回该结点的引用,方便调用程序处理。
96+
## 插入结点
97+
插入结点就是在链表中间部分的指定位置增加一个结点。插入结点的操作步骤如下:
98+
1. 分配内存空间,保存新增的结点。
99+
- 找到要插入的逻辑位置,也就是那两个结点之间。
100+
- 使新增节点指向原插入位置所指向的结点,并修改插入位置结点的引用,使其指向新增结点。
101+
102+
CLType CLInsertNode(CLType head, String findKey, DATA nodeData){ // 插入关键字结点
103+
CLType node, nodetemp;
104+
if((node = new CLType())==null){
105+
System.out.println("申请内存失败!\n");
106+
return null;
107+
}
108+
node.nodeData = nodeData;
109+
nodetemp = CLFindNode(head, findKey); // 获取插入位置关键字所指代的结点
110+
if(nodetemp == null){
111+
System.out.println("未找到正确的插入位置!\n");
112+
}else{
113+
node.nextNode = nodetemp.nextNode; // 新插入的节点的nextNode指向关键字结点的下一结点
114+
nodetemp.nextNode = node; // 设置关键结点指向新插入结点
115+
}
116+
return head;
117+
}
118+
## 删除结点
119+
删除结点就是将链表中的某个结点数据删除。删除结点的操作步骤如下:
120+
1. 查找需要删除的结点。
121+
- 使前一结点指向当前结点的下一结点。
122+
- 删除结点。
123+
124+
int CLDeleteNode(CLType head, String key){ // 删除关键字结点
125+
CLType htemp,tempnode;
126+
if(head == null){
127+
return 0;
128+
}
129+
htemp = head;
130+
tempnode = head;
131+
while(htemp != null){
132+
if(htemp.nodeData.key.compareTo(key)==0){ // 遍历查找
133+
tempnode.nextNode = htemp.nextNode; // 当前结点的引用指向下一个结点的引用,以此删除htemp结点
134+
return 1;
135+
}
136+
tempnode = htemp; // 保存当前结点
137+
htemp = htemp.nextNode; // 指向下一个结点
138+
}
139+
return 0;
140+
}
141+
注意,此时被删除结点仍然保存在内存中,接着执行赋值null操作,用来释放被删除节点所占用的内存空间。
142+
## 计算链表长度
143+
统计链表结构中结点的数量,由于链表结构在物理上不是连续存储的,因此,需要遍历整个链表来对结点数量进行累加。
144+
145+
int CLLength(CLType head){ //返回结点总数
146+
CLType htemp;
147+
int len = 0;
148+
htemp = head;
149+
while(htemp!=null){ // 循环遍历累计总结点数
150+
len++;
151+
htemp=htemp.nextNode;
152+
}
153+
return len;
154+
}
155+
程序中通过while循环来遍历整个链表,从而累加数量并返回。
156+
157+
## 显示所有结点
158+
159+
void CLAllNode(CLType head){ // 遍历链表输出所有数据
160+
CLType htemp;
161+
htemp = head;
162+
System.out.printf("\n当前链表共有%d个结点。链表所有数据如下:\n",CLLength(head));
163+
while(htemp != null){
164+
System.out.printf("结点(%s,%s,%d)\n",htemp.nodeData.key, htemp.nodeData.name, htemp.nodeData.age);
165+
htemp = htemp.nextNode;
166+
}
167+
}
168+
169+
## 链表操作实例
170+
完整实例源码:
171+
[LinkedList.java](./LinkedList.java)

src/dataStructure/orderList/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# 顺序表结构
1+
# 顺序表结构 :green_apple:
22
顺序表(Sequential List)就是按照顺序存储方式存储的线性表,该线性表的结点按照逻辑次序依次存放在计算机的一组连续的存储单元中。
33

44
由于顺序表是一次存放的,只要知道了该顺序表的首地址及每个数据元素所占用的存储长度,那么就很容易计算出任何一个数据元素(即数据结点)的位置。
@@ -123,5 +123,5 @@
123123
}
124124

125125
## 顺序操作表实例
126-
源码
126+
完成实例源码
127127
[OrderList.java](./OrderList.java)

src/dataStructure/stack/README.md

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,107 @@
1-
# 栈结构
1+
# 顺序栈结构
2+
3+
## 准备数据
4+
class DATA{
5+
String name;
6+
int age;
7+
}
8+
9+
/*
10+
* 顺序栈结构
11+
*/
12+
class StackType{
13+
static final int MAXLEN = 50;
14+
DATA[] data = new DATA[MAXLEN+1]; // 构建栈结构
15+
int top; // 栈顶
16+
}
17+
在上述代码中,定义了栈结构的最大长度MAXLEN,栈结构数据元素的类DATA及栈结构的类StackType。在类StackType中,data为数据元素,top为栈顶的序号。当top=0时表示栈为空,当top=SIZE时表示栈满。
18+
19+
Java语言中数组都是从下标0开始的。在这里,为了讲述和理解的方便,从下标1开始记录数据结点,下标0的位置不使用。
20+
## 初始化栈结构
21+
顺序栈的初始化操作步骤:
22+
1. 按符号常量SIZE指定的大小申请一片内存空间,用来保存栈中的数据。
23+
- 设置栈顶引用的值为0,表示一个空栈。
24+
StackType STInit(){ // 栈的初始化
25+
StackType p;
26+
if((p=new StackType())!=null){ // 申请栈内存
27+
p.top = 0; // 设置栈顶为0
28+
return p; // 返回指向栈的引用
29+
}
30+
return null;
31+
}
32+
33+
## 判断空栈
34+
判断空栈即判断一个栈结构是否为空。如果是空栈,则表示该结构中没有数据。此时可以进行入栈操作,但不可以进行出栈操作。
35+
36+
boolean STIsEmpty(StackType s){ // 判断栈是否为空
37+
return s.top==0;
38+
}
39+
40+
## 判断满栈
41+
如果是满栈,则表示该结构中没有多余的空间来保存额外数据。此时不可以进行入栈操作,但是可以进行出栈操作。
42+
43+
boolean STIsFull(StackType s){ // 判断栈是否已满
44+
return s.top==MAXLEN;
45+
}
46+
47+
## 清空栈
48+
清空栈即清除栈中的所有数据,在程序中简单地将栈顶引用top设置为0,表示执行清空栈操作。
49+
50+
void STClear(StackType s){ // 清空栈
51+
s.top = 0;
52+
}
53+
54+
## 释放空间
55+
释放空间即释放栈结构所占用的内存单元,程序中,直接赋值null操作释放所分配的内存。一般在不需要使用栈结构的时候使用,特别是程序结束时。
56+
57+
void STFree(StackType s){ // 释放栈所占用的空间
58+
if(s != null){
59+
s = null;
60+
}
61+
}
62+
63+
## 入栈
64+
入栈(Push)是栈结构的基本操作,主要操作是将数据元素保存到栈结构。
65+
1. 首先判断栈顶top,如果top大于等于SIZE,则表示溢出,进行出错处理;否则执行以下操作。
66+
2. 设置top=top+1(栈顶引用加1,指向入栈地址)。
67+
- 将入栈元素保存到top指向的位置。
68+
69+
int PushST(StackType s, DATA data){ // 入栈
70+
if(s.top+1 > MAXLEN){
71+
System.out.println("栈溢出!\n");
72+
return 0;
73+
}
74+
s.data[++s.top] = data; // 元素入栈,top指针+1
75+
return 1;
76+
}
77+
78+
## 出栈
79+
出栈(Pop)是栈结构的基本操作,主要操作与入栈相反,其操作是栈顶弹出一个数据元素。出栈操作的基本步骤如下:
80+
1. 判断栈顶top,如果top等于0,则表示为空栈,进行出错处理;否则,执行下面的步骤。
81+
2. 将栈顶引用top所指位置的元素返回。
82+
3. 设置top=top-1,也就是使栈顶引用减1,指向栈的下一个元素,原来栈顶元素被弹出。
83+
84+
DATA PopST(StackType s){ // 出栈
85+
if(s.top==0){
86+
System.out.println("栈为空!\n");
87+
return null;
88+
}
89+
return s.data[s.top--]; // 元素出栈,top指针-1
90+
}
91+
92+
## 读结点数据
93+
读结点数据即读取栈结构中结点的数据。由于栈结构只能在一段进行操作,因此这里的读操作其实就是读取栈顶的数据。
94+
95+
需要注意的是,读结点数据的操作和出栈的操作不同。读结点数据的操作仅显示栈顶结点数据的内容,而出栈操作则是将栈顶数据弹出,该数据不再存在了。
96+
97+
DATA PeekST(StackType s){ // 读栈顶数据
98+
if(s.top==0){
99+
System.out.println("栈为空! 出栈失败!\n");
100+
System.exit(0);
101+
}
102+
return s.data[top];
103+
}
104+
105+
## 栈结构操作实例
106+
操作实例源码
107+
[Stack.java](./Stack.java)

0 commit comments

Comments
 (0)