您的位置:首页 > 理论基础 > 数据结构算法

(转)java实现基本数据结构(堆,栈,链表)——推荐后面的链表扩展部分

2016-03-20 20:51 851 查看
以下是算法导论第十章的学习笔记。出处 http://segmentfault.com/blog/exploring/


1 栈

栈顶指针 top (初始值top = -1)指向栈顶元素,插入时先修改指针再插入,删除时先取栈顶元素再修改指针.


1.1 性质

后进先出

入栈,出栈都是
O(1)


1.2 核心代码

public class Stack {
private int[] array = new int[5];
private int top = -1;

public Boolean stackempty(){
if(top == -1){
return true;
}
else
return false;
}

public void push(int x){
if(top<=array.length-1){
array[++top] = x;
}
else{
System.out.println("overflow");
}
}

public int pop() {
int number = -1;
if(stackempty() != true){
number = array[top];
top--;
return number;
}
else
{
System.out.println("underflow");
return -1;
}
}



2 队列

array
数组实现的至多含有
n-1
个元素的队列的方法.

队列具有属性
head[Q]
,指向队列的头. 属性
tail[Q]
指向新元素要被插入的地方

head[Q] = tail[Q]
时,队列空;

head[Q] = tail[Q]+1
时,队列满;

初始
head[Q] = tail[Q] = 1


2.1 性质

先进先出

入队,出队都是
O(1)





2.2 核心代码

public class Queue {
private int[] array = new int[4];
private int head = 1;
private int tail = 1;
//入队
public void enqueue(int x){
//处理上溢
try{
if(head != tail +1){
array[tail++] = x;
if(tail == array.length){
tail = 0;
}
}
else{
System.out.println("overflow");
throw new Exception("queue overflow");
}
}catch(Exception e){
e.printStackTrace();
}
}

//出队
public int dequeue(){
int number=0;
try{
if(tail != head){
number = array[head];
head++;
}
else{
throw new Exception("queue underflow");
}

}catch(Exception e){
System.out.println("underflow");
e.printStackTrace();
}
return number;
}



3. (双向)链表

链表是面试时被频繁提及的DS。 每个对象包括一个关键字域和两个指针域prev,next;

链表为什么这么受欢迎?

链表是一种动态的数据结构,其操作需要通过指针进行。链表内存的分配不是在创建链表时一次性完成,而是每添加一个节点就分配一次内存。由于没有闲置内存。他的空间效率比数组更高。

通过使用哨兵nil节点(增加一个nil节点)可以简化边界条件。


3.1 性质

相对于数组,长度可变;插入删除更容易。


3.2核心代码

(单向链表)
全选<button href="javascript:void(0);" _xhe_href="javascript:void(0);" class="copyCode btn btn-xs zeroclipboard-is-hover" data-clipboard-text="" public="" linkedlist="" {"="" data-toggle="tooltip" data-placement="top" title="" style="color: rgb(255, 255, 255); font-family: inherit; font-style: inherit; font-variant: inherit; line-height: 1.5; margin: 0px 0px 0px 5px; overflow: visible; cursor: pointer; vertical-align: middle; border: 1px solid transparent; white-space: nowrap; padding-right: 5px; padding-left: 5px; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; -webkit-user-select: none; box-shadow: rgba(0, 0, 0, 0.2) 0px 1px 2px; background-color: rgba(0, 0, 0, 0.74902);">复制放进笔记[code]public class LinkedList {
private Node head;
private Stack s;
LinkedList(){
head = null;
s = new Stack();
}
private static class Node{
int item;
Node next;

Node(){
this.item = 0;
this.next = null;
}
Node(int item, Node next){
this.item = item;
this.next = next;
}
}

public void insert(int x){
Node node = new  Node(x, null);
Node p = head;
// 注意链表为空的时候的插入
if(head==null){
head = node;
}
// 尾插法
else{
while(p.next != null){
p = p.next;
}
p.next = node;
}
}
public void travese(Node head){
Node p = head;
while(p!=null){
System.out.println(p.item);
p = p.next;
}
}


(双向链表)



public class DoubleLinkedList {
// 哨兵节点nil(作为表头指针)
private Node nil;
// 初始化一个链表
DoubleLinkedList(){
nil = new Node();
nil.next = nil;
nil.prev = nil;
count = 0;
}
// 链表长度
private int count;
private static class Node{
int item;
Node next;
Node prev;

Node(){
item = 0;
next = null;
prev = null;
}
Node(int item, Node next, Node prev){
this.item = item;
this.next = next;
this.prev = prev;
}
}

//返回当前链表的长度
public int length(){
return count;
}

//获取value为k的节点
public Node listsearch(int k){
Node result = null;
Node head = nil;
while(head.next != nil){
if(head.next.item == k){
result = head.next;
break;
}
else
head = head.next;
}
return result;
}

//插入一个节点在队首
public void listinsert(Node node){
node.next = nil.next;
nil.next.prev = node;
nil.next = node;
node.prev = nil;
count++;
}
//根据value删除一个节点
public Node listdelete(Node node){
Node head = nil;
Node nodetodelete;
while(head.next!=nil){
if(head.next.item == node.item){
nodetodelete = head.next; //将要删除的节点
head.next = nodetodelete.next;
nodetodelete.next.prev  = head;
nodetodelete = null;

count--;
}
else{
head = head.next;
}
}
return node;
}
//输出链表
public void traverse(){
Node head = nil;
while( head.next!= nil){
System.out.println(head.next.item);
head = head.next;
}
}


3.3 扩展


1. 从尾到头打印链表

题目:输入一个链表的头节点,从尾到头打印出来每个节点的值。

解法:遍历,每遍历到的元素存到栈,然后输出栈即可。

代码:
public void reveaseoutput(Node head){
Node p = head;
if(p==null){
System.out.println("empty list");
}
while(p != null){
s.push(p.item);
p = p.next;
}
while(s.stackempty()!= true){
int n = s.pop();
System.out.println(n);
}
}


2.
O(1)
时间删除链表节点

题目:给定单链表的头指针和一个节点指针,
O(1)
时间删除该链表节点

解法:下一个节点的内容复制到需要删除的点,即覆盖。然后删该店的下一个节点。

这里需要考虑两个边界条件,1 要删除的点位于尾部 2 链表只有一个节点

要考虑鲁棒性。

代码:
public void deleteNode(Node head, Node pToDeleted){
if(head!=null){
//要删除的是尾节点
if(pToDeleted.next == null){
//如果要删除的是链表唯一的节点
if(head.next==null){
head = null;
System.out.println(head);
pToDeleted = null;
}
else{
Node p = head;
while(p.next!=pToDeleted){
p = p.next;
}
p.next = null;
pToDeleted =null;
}
}
//要删除的不是尾节点,且节点数大于1
else{
pToDeleted.item = pToDeleted.next.item;
pToDeleted.next = pToDeleted.next.next;
pToDeleted = null;
}

}else{
System.out.println("the linklist is empty");
}
}


3. 倒数第k个节点

题目:输入一个链表,输出该链表第倒k个节点。(链表从1开始计数)

解法:定义两个指针,第一个指针从链表的head指针开始遍历,向前走k-1步的时候,第二个指针开始和它一起走。当第一个指针的next指向null的时候,第二个指针指向了倒数第k个。(这种一次遍历,对时间要求比较高的程序,就需要借助空间,再开辟一个指针)

要考虑鲁棒性。

代码:
//遍历链表一次,删除倒数第K个元素
public Node FindKthToTail(Node head, int k){
Node p=head;
Node q = head;
int i;
if(head==null || k==0){
return null;
}
for(i=0;i<k-1;i++){
if(p.next !=null){
p = p.next;
}
else{//当k大于链表的长度的时候
System.out.println("error k");
return null;
}

}

while(p.next!=null){
p = p.next;
q = q.next;
}
return q;
}


4. 反转链表

题目:定义一个函数,输入链表头节点,反转该链表并输出反转后链表的头节点。

解法:借助三个指针,prev, p, next. 避免指针断裂。

( 为了正确的反转一个链表,需要调整链表中指针的方向【指针反向】。注意,在单链表中,将一个节点的指向后继的指针指向它的前驱,将会导致链表的断裂。导致无法在单链表中遍历它的后继节点,因此,在调整某一节点的 next 指针时,需要首先将其的后继节点保存下来。)



代码:
public Node reverse(){
Node p = head;
try{
if(p!=null){
Node pnext = p.next;
p.next = null;
while(pnext!= null){
Node r = pnext.next;
pnext.next = p;
p = pnext;
pnext = r;
}
}else{
throw new Exception("empty list");
}
}catch(Exception e){
e.printStackTrace();
}finally{
return p;
}
}



5 合并链表

题目:输入两个增序的链表,合并这两个链表并使新链表仍然增序。

解法:重点强调鲁棒性:两个链表一个或者两个都是null,两个链表只有一个节点。

代码:
public Node merge(Node head1, Node head2){
if(head1 == null) {
return head2;
}
if(head2 == null){
return head1;
}
else{
Node newhead;
Node r;
Node p = head1;
Node q = head2;

if(head1.item <= head2.item){
newhead = head1;
p = p.next;
}
else{
newhead = head2;
q = q.next;
}
r = newhead;

while(p!=null && q!=null){
if(p.item <= q.item){
r.next = p;
p = p.next;
r = r.next;
}
else{
r.next = q;
q = q.next;
r = r.next;
}
}

if(p!=null){
r.next = p;
}
if(q!=null){
r.next = q;
}
return newhead;
}
}



6 复杂链表的复制

题目:


解法:


代码:
//1. 根据原始链表的每个节点创建对应的copy节点
public void CloneNode(ComplexNode head){
ComplexNode p = head;
while(p!=null){
ComplexNode node = new ComplexNode(p.item,null,null);
node.next = p.next;
p.next = node;
p = node.next;
}
}

//2. 设置复制出来的节点的sibling
public void connectsiblingnodes(ComplexNode head){
ComplexNode p = head;

while(p!=null){
ComplexNode q = p.next;
if(p.sibling!=null)
{
q.sibling = p.sibling.next;
}
p = q.next;

}
}

//3. 拆分链表
public ComplexNode ReconnectNodes(ComplexNode head){
ComplexNode p = head;
if(p!=null){
ComplexNode newhead = p.next;
ComplexNode q = newhead;
while(q.next!=null){
p.next = q.next;
p = q.next;
q.next = p.next;
q = p.next;
}
return newhead;
}
else{
return null;
}
}


7 寻找第一个公共节点

题目:输入两个链表,找出第一个公共节点。

解法:Y形

代码:
public Node findfirstcommonnode(Node head1, Node head2){
Node p = head1;Node q = head2;
int length = int length1 = int length2= 0;
while(p!=null){
length1 = length1 + 1;
p = p.next;
}
while(q!=null){
length2 = length2 + 1;
q = q.next;
}

p = head1;q = head2;

if(length1>length2){
length = length1 - length2;
while(length>0){
p = p.next; length--;
}
}
if(length1<length2){
length = length2 - length1;
while(length>0){
q = q.next; length--;
}
}
while(p!=null&&q!=null&&p.item != q.item){
p = p.next; q = q.next;
}
return p;
}


想更一进步的支持我,请扫描下方的二维码,你懂的~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: