0% found this document useful (0 votes)
46 views32 pages

Csci 210: Data Structures Linked Lists

The document discusses linked lists and their implementation in Java. Key points include: - Linked lists allow dynamic sizes and have faster insertion/deletion at the head than arrays but slower access to arbitrary elements. - A linked list node class stores an element and a reference to the next node. A list class tracks the head and size. - Common single linked list operations like addFirst, removeFirst are O(1) time while operations involving the tail like addLast are O(n) due to lack of direct tail access. - Doubly linked lists add a previous pointer, allowing O(1) time for all common operations by traversing in either direction. - Sentinel nodes can simplify

Uploaded by

mekko_007
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
46 views32 pages

Csci 210: Data Structures Linked Lists

The document discusses linked lists and their implementation in Java. Key points include: - Linked lists allow dynamic sizes and have faster insertion/deletion at the head than arrays but slower access to arbitrary elements. - A linked list node class stores an element and a reference to the next node. A list class tracks the head and size. - Common single linked list operations like addFirst, removeFirst are O(1) time while operations involving the tail like addLast are O(n) due to lack of direct tail access. - Doubly linked lists add a previous pointer, allowing O(1) time for all common operations by traversing in either direction. - Sentinel nodes can simplify

Uploaded by

mekko_007
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 32

csci 210: Data Structures

Linked lists
Summary
Today
linked lists
single-linked lists
double-linked lists
circular lists
READING:
GT textbook chapter 3.2. 3.3. 3.4
Arrays vs. Linked Lists
Weve seen arrays:
int[] a = new int[10];
a is a chunk of memory of size 10 x sizeof(int)
a has a xed size
A linked list is fundamentally different way of storing collections
each element stores a reference to the element after it
a[0] a[1] a[2] ... a[9]
null
Arrays vs. Lists
Arrays
have a pre-determined xed size
easy access to any element a[i] in constant time
no space overhead
Size = n x sizeof(element)
Linked lists
no xed size; grow one element at a time
space overhead
each element must store an additional reference
Size = n x sizeof (element) + n x sizeof(reference)
no easy access to i-th element wrt the head of the list
need to hop through all previous elements
The Node class
/** Node of a singly linked list of integers */
public class Node {

private int element; // we assume elements are ints
private Node next;
int
next
self-referential denition
The Node class
/** Node of a singly linked list of integers */
public class Node {
private int element; // we assume elements are ints
private Node next;
/** Creates a node with the given element and next node. */
public Node(Int s, Node n) {
element = s;
next = n;
}
/** Returns the element of this node. */
public int getElement() { return element; }
/** Returns the next node of this node. */
public Node getNext() { return next; }
// Modifier methods:
/** Sets the element of this node. */
public void setElement(int newElem) { element = newElem; }
/** Sets the next node of this node. */
public void setNext(Node newNext) { next = newNext; }
}
int
next
A Single-Linked-List class
/** Singly linked list .*/
public class SLinkedList {
protected Node head; // head node of the list
protected long size; // number of nodes in the list
/** Default constructor that creates an empty list */
public SLinkedList() {
head = null;
size = 0;
}
null
head
A Single-Linked-List class
/** Singly linked list .*/
public class SLinkedList {
protected Node head; // head node of the list
protected long size; // number of nodes in the list
/** Default constructor that creates an empty list */
public SLinkedList() {
head = null;
size = 0;
}
}
well discuss the following methods
addFirst(Node n)
addAfter(Node n)
Node get(int i)
Node removeFirst()
addLast(Node n)
removeLast(Node n)
null
head
void addFirst(Node n) {
n.setNext(head);
head = n;
size++;
}
Notes
Special cases: works when head is null, i.e. list is empty
Efciency: O(1) time (i.e. constant time)
null
head
null
head
n
Inserting at head
void addFirst(Node n)
Inserting in the middle
//insert node n after node v
void insertAfter(Node v, Node n)
n.setNext(v.getNext());
v.setNext(n);
size++;
}
Notes:
Efciency: O(1) (constant time)
Special cases
does not work if v or n are null
null pointer exception
null
head
v
n
n
null
v
void insertAfter(Node v, Node n)
Get the i-th element
//return the i-th node
Node get(int i)
Get the i-th element
//return the i-th node
Node get(int i) {
if (i >= size) print error message and return null
Node ptr = head;
for (int k=0; k<i; k++)
ptr = ptr.getNext();
return ptr;
}
Notes
Special cases
does it work when list is empty?
Efciency: takes O(i) time
constant time per element traversed
unlike arrays, accessing i-th element is not constant time
Remove at head
Node removeFirst() {
Node n = head;
head = head.getNext();
n.setNext(null);
return n;
}
Notes:
Special cases
does it work when list is empty?
Nope.
How to x it?
Efciency: O(1)
null
head
head
Insert at tail
void addLast(Node n) {
insertAfter (get(size), n);
}
Notes
Special cases
does it work when list is empty?
Nope (rst node in insertAfter is null).
How to x it?
Efciency: takes O(size) time
Delete at tail
Remove at end: similar
need to get to the last element from the head
O(size) time
Linked lists
Single-linked lists support insertions and deletions at head in O(1) time.
insertions and deletion at the tail can be supported in O(size) time.
addFirst: O(1) time (constant time)
removeFirst: O(1) time (constant time)
addLast: O(size) time
removeLast: O(size) time
Why? because we keep track of the head.
To access the tail in constant time, need to keep track of tail as well.
Linked-list with tail
/** Singly linked list .*/
public class SLinkedList {
private Node head, tail; // head and tail nodes of the list
private long size; // number of nodes in the list
void SLinkedList() {
head = tail = null;
size = 0;
}
void addFirst(Node n) {...}
Node removeFirst() {...}
....
}
all methods must update tail
Insert at tail
Special cases: list is empty
void addLast(Node n) {
//if list is empty the new element is head and tail
if (tail == null) {
n.setNext(null);
head = tail = n;
} else {
//the list is not empty: link tail to n and n becomes the new tail
tail.setNext(n);
n.setNext(null);
tail = n;
}
//increment size
size++
}
Efciency: O(1)
Remove at tail
What we want: delete the last element and set the new tail
Is that possible?
Remove at tail
What we want: delete the last element and set the new tail
Is that possible?
Remove at tail
set the tail to the node BEFORE the tail
need the node before the tail: O(size)
To remove an element from a list you need the node BEFORE it as well
remove(Node n) {
//link n.before to n.next
}
To remove a node efciently need to keep track of previous node
Doubly-linked lists
/** Node of a doubly linked list of integers */
public class DNode {
protected int element; //element stored by a node
protected DNode next, prev; // Pointers to next and previous nodes
/** Constructor that creates a node with given fields */
public DNode(int e, DNode p, DNode n) {
element = e;
prev = p;
next = n;
}
/** Returns the element of this node */
public int getElement() { return element; }
/** Returns the previous node of this node */
public DNode getPrev() { return prev; }
/** Returns the next node of this node */
public DNode getNext() { return next; }
/** Sets the element of this node */
public void setElement(Int newElem) { element = newElem; }
/** Sets the previous node of this node */
public void setPrev(DNode newPrev) { prev = newPrev; }
/** Sets the next node of this node */
public void setNext(DNode newNext) { next = newNext; }
}
int
next prev
Doubly-linked lists
/** Doubly linked list with nodes of type DNode */
public class DList {
protected int size; // number of elements
protected DNode head, tail;
void addFirst(Node n);
void addLast(Node n);
Node deleteFirst();
Node deleteLast();
void delete(Node n);
}
Operations on doubly linked lists
addFirst(): O(1) time
addLast(): O(1) time
deleteFirst(): O(1) time
deleteLast(): O(1) time
delete(): O(1) time
get(i): O(i) time
Insert at head
void addFirst(Node n) {
n.setNext(head);
n.setprev(null);
head.setPrev(n);
head = n;
size++;
}
Does this work?
Insert at head
void addFirst(Node n) {
n.setNext(head);
n.setprev(null);
head.setPrev(n);
head = n;
size++;
}
Special cases?
empty list: head is null; need to set tail too
void addFirst(Node n) {
if (head==null) {
//this is the first element: set both head and tail to it
head = tail = n;
n.setPrev(null); n.setNext(null);
}
else {
n.setNext(head); n.setprev(null);
head.setPrev(n);
head = n;
}
size++;
}
Efficiency: O(1)
Insert at tail
void addLast(Node n) {
tail.setNext(n);
n.setprev(tail);
n.setNect(null);
tail = n;
size++;
}
Does this work ?
Insert at tail
void addLast(Node n) {
tail.setNext(n);
n.setprev(tail);
n.setNect(null);
tail = n;
size++;
}
Special cases?
empty list: tail is null; need to set head too
void addLast(Node n) {
if (tail == null) {
head = tail = n; n.setPrev(null); n.setNext(null);
}
else {
tail.setNext(n); n.setprev(tail); n.setNect(null);
tail = n;
}
size++;
}

Efficiency: O(1)
Doubly-linked lists
Class work: Sketch the following methods for doubly-linked lists, and analyze their efciency.
Node removeFirst()
Node removeLast()
void remove(Node n)
Node search(int k)
Sentinels
Sentinels for singly-linked list: keep a dummy head
an empty list is one node: the dummy head
Sentinels for doubly-linked lists
dummy head and dummy tail
Why? elegant. Unies special cases when head or tail are null

DLLists with Sentinels
public class DList {

protected int size; // number of elements
protected DNode header, trailer;// sentinels
/** Constructor that creates an empty list */
public DList() {
size = 0;
header = new DNode(null, null, null); // create header
trailer = new DNode(null, header, null); // create trailer
// make header and trailer point to each other
header.setNext(trailer);

}
the empty list:
size = 0
dummyhead dummytail
DLLists with sentinels
insertFirst(Node n) {
n.setNext(dummyHead.getNext());
dummyHead.getNext().setPrev(n);
dummyHead.setNext(n);
n.setPrev(dummyhead);
size++;
}
Special cases: none
works for empty list
dummyhead dummytail
dummyhead dummytail
Extensions
Circular lists
make last node point to the rst (instead of null)
class CircularList {
SNode head;
int size;
}
lets say we want to insert at head
insertAtHead(Node n) {
n.setNext(head.getNext());
head.setNext(n);
}
if head is null?
if (head ==null) {
n.setNext(n);
head = n;
}
head
Linked-lists in Java
search for class Java Linked List
has all expected methods and features

You might also like