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

Csci 210: Data Structures Linked Lists

This document discusses different types of linked lists, including single-linked lists, doubly-linked lists, and circular lists. It provides code examples for Node and LinkedList classes to implement a basic single-linked list with methods for adding and removing elements from the head and tail. It notes that single-linked lists allow efficient insertion and deletion at the head, but insertion and deletion at the tail require O(n) time. Doubly-linked lists are also introduced, which allow efficient insertion and deletion from both ends by maintaining references to both the previous and next node.

Uploaded by

DasikaPushkar
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)
68 views32 pages

Csci 210: Data Structures Linked Lists

This document discusses different types of linked lists, including single-linked lists, doubly-linked lists, and circular lists. It provides code examples for Node and LinkedList classes to implement a basic single-linked list with methods for adding and removing elements from the head and tail. It notes that single-linked lists allow efficient insertion and deletion at the head, but insertion and deletion at the tail require O(n) time. Doubly-linked lists are also introduced, which allow efficient insertion and deletion from both ends by maintaining references to both the previous and next node.

Uploaded by

DasikaPushkar
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 fixed size

a[0] a[1] a[2] ... a[9]

A linked list is fundamentally different way of storing collections


each element stores a reference to the element after it

null
Arrays vs. Lists

Arrays
have a pre-determined fixed size
easy access to any element a[i] in constant time
no space overhead
Size = n x sizeof(element)

Linked lists
no fixed 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
next
int
/** Node of a singly linked list of integers */
public class Node {

private int element; // we assume elements are ints


private Node next;

self-referential definition
The Node class
next
int
/** 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; }
}
A Single-Linked-List class
head
null
/** 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;
}
A Single-Linked-List class
head
null
/** 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)
Inserting at head

head
null
n

void addFirst(Node n)

head

null

void addFirst(Node n) {
n.setNext(head);
head = n;
size++;
}

Notes
Special cases: works when head is null, i.e. list is empty
Efficiency: O(1) time (i.e. constant time)
Inserting in the middle
v
head
null

void insertAfter(Node v, Node n)

v
n
null

//insert node n after node v


void insertAfter(Node v, Node n)
n.setNext(v.getNext());
v.setNext(n);
size++;
}
Notes:
Efficiency: O(1) (constant time)
Special cases
does not work if v or n are null
null pointer exception
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?
Efficiency: takes O(i) time
constant time per element traversed
unlike arrays, accessing i-th element is not constant time
Remove at head
head head
null

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 fix it?
Efficiency: O(1)
Insert at tail
void addLast(Node n) {
insertAfter (get(size), n);
}

Notes
Special cases
does it work when list is empty?
Nope (first node in insertAfter is null).
How to fix it?
Efficiency: 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() {
all methods must update tail
head = tail = null;
size = 0;
}

void addFirst(Node n) {...}

Node removeFirst() {...}

....
}
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++
}

Efficiency: 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 efficiently need to keep track of previous node


Doubly-linked lists
prev next
int

/** 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; }
}
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 efficiency.

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. Unifies 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

dummyhead dummytail

insertFirst(Node n) {
n.setNext(dummyHead.getNext());
dummyHead.getNext().setPrev(n);
dummyHead.setNext(n);
n.setPrev(dummyhead);
dummyhead dummytail
size++;
}

Special cases: none


works for empty list
Extensions

Circular lists
make last node point to the first (instead of null)

class CircularList {
SNode head;
int size;
head
}

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;
}
Linked-lists in Java

search for class Java Linked List


has all expected methods and features

You might also like