Vous êtes sur la page 1sur 21

1.

Reverse a Doubly Linked List

2. Write a recursive function treeToList(Node root) that takes an ordered binary tree and
rearranges the internal pointers to make a circular doubly linked list out of the tree nodes.
The”previous” pointers should be stored in the “small” field and the “next” pointers should be
stored in the “large” field. The list should be arranged so that the nodes are in increasing order.
Return the head pointer to the new list.

3. QuickSort on Doubly Linked List

4. Merge Sort for Doubly Linked List

5. Find pairs with given sum in doubly linked list

6. Insert value in sorted way in a sorted doubly linked list

7. Delete a Doubly Linked List node at a given position

8. Count triplets in a sorted doubly linked list whose sum is equal to a given value x (hashing)

9. Remove duplicates from a sorted doubly linked list

10. Delete all occurrences of a given key in a doubly linked list

11. Remove duplicates from an unsorted doubly linked list(hashing)

12. Convert a given Binary Tree to Doubly Linked List

13. QuickSort on Singly Linked List

14. Iterative Quick sort

15. Merge sort for linked list

16. Why Quick Sort preferred for Arrays and Merge Sort for Linked Lists?

ans: (i) Quick Sort in its general form is an in-place sort (i.e. it doesn’t require any extra storage)
whereas merge sort requires O(N) extra storage, N denoting the array size which may be quite
expensive. Allocating and de-allocating the extra space used for merge sort increases the
running time of the algorithm.

Comparing average complexity we find that both type of sorts have O(NlogN) average
complexity but the constants differ. For arrays, merge sort loses due to the use of extra O(N)
storage space.

Most practical implementations of Quick Sort use randomized version. The randomized version
has expected time complexity of O(nLogn). The worst case is possible in randomized version also,
but worst case doesn’t occur for a particular pattern (like sorted array) and randomized Quick
Sort works well in practice.

Quick Sort is also a cache friendly sorting algorithm as it has good locality of reference when
used for arrays.

(ii) In case of linked lists the case is different mainly due to difference in memory allocation of
arrays and linked lists. Unlike arrays, linked list nodes may not be adjacent in memory.

Unlike array, in linked list, we can insert items in the middle in O(1) extra space and O(1) time.
Therefore merge operation of merge sort can be implemented without extra space for linked
lists.

In arrays, we can do random access as elements are continuous in memory. Let us say we have
an integer (4-byte) array A and let the address of A[0] be x then to access A[i], we can directly
access the memory at (x + i*4). Unlike arrays, we can not do random access in linked list.

Quick Sort requires a lot of this kind of access. In linked list to access i’th index, we have to travel
each and every node from the head to i’th node as we don’t have continuous block of memory.
Therefore, the overhead increases for quick sort. Merge sort accesses data sequentially and the
need of random access is low.

1.

/* Program to reverse a doubly linked list */

#include <stdio.h>

#include <stdlib.h>

/* a node of the doubly linked list */

struct Node

{ int data;

struct Node *next;

struct Node *prev; };

/* Function to reverse a Doubly Linked List */

void reverse(struct Node **head_ref)


{ struct Node *temp = NULL;

struct Node *current = *head_ref;

/* swap next and prev for all nodes of

doubly linked list */

while (current != NULL)

{ temp = current->prev;

current->prev = current->next;

current->next = temp;

current = current->prev; }

/* Before changing head, check for the cases like empty

list and list with only one node */

if(temp != NULL )

*head_ref = temp->prev; }

/* UTILITY FUNCTIONS */

/* Function to insert a node at the beginging of the Doubly Linked List */

void push(struct Node** head_ref, int new_data)

{ /* allocate node */

struct Node* new_node =

(struct Node*) malloc(sizeof(struct Node));

/* put in the data */

new_node->data = new_data;
/* since we are adding at the begining,

prev is always NULL */

new_node->prev = NULL;

/* link the old list off the new node */

new_node->next = (*head_ref);

/* change prev of head node to new node */

if((*head_ref) != NULL)

(*head_ref)->prev = new_node ;

/* move the head to point to the new node */

(*head_ref) = new_node; }

/* Function to print nodes in a given doubly linked list

This function is same as printList() of singly linked lsit */

void printList(struct Node *node)

{ while(node!=NULL)

{ printf("%d ", node->data);

node = node->next; } }

2.

// A function that appends rightList at the end

// of leftList.

Node *concatenate(Node *leftList, Node *rightList)


{

// If either of the list is empty

// then return the other list

if (leftList == NULL)

return rightList;

if (rightList == NULL)

return leftList;

// Store the last Node of left List

Node *leftLast = leftList->left;

// Store the last Node of right List

Node *rightLast = rightList->left;

// Connect the last node of Left List

// with the first Node of the right List

leftLast->right = rightList;

rightList->left = leftLast;

// Left of first node points to

// the last node in the list

leftList->left = rightLast;

// Right of last node refers to the first

// node of the List


rightLast->right = leftList;

return leftList;

// Function converts a tree to a circular Linked List

// and then returns the head of the Linked List

Node *bTreeToCList(Node *root)

if (root == NULL)

return NULL;

// Recursively convert left and right subtrees

Node *left = bTreeToCList(root->left);

Node *right = bTreeToCList(root->right);

// Make a circular linked list of single node

// (or root). To do so, make the right and

// left pointers of this node point to itself

root->left = root->right = root;

// Step 1 (concatenate the left list with the list

// with single node, i.e., current node)

// Step 2 (concatenate the returned list with the

// right List)
return concatenate(concatenate(left, root), right);

3.

/* Considers last element as pivot, places the pivot element at its

correct position in sorted array, and places all smaller (smaller than

pivot) to left of pivot and all greater elements to right of pivot */

Node* partition(Node *l, Node *h)

{ // set pivot as h element

int x = h->data;

// similar to i = l-1 for array implementation

Node *i = l->prev;

// Similar to "for (int j = l; j <= h- 1; j++)"

for (Node *j = l; j != h; j = j->next)

if (j->data <= x)

// Similar to i++ for array

{ i = (i == NULL)? l : i->next;

swap(&(i->data), &(j->data)); } }

i = (i == NULL)? l : i->next; // Similar to i++

swap(&(i->data), &(h->data));

return i; }
/* A recursive implementation of quicksort for linked list */

void _quickSort(struct Node* l, struct Node *h)

{ if (h != NULL && l != h && l != h->next)

{ struct Node *p = partition(l, h);

_quickSort(l, p->prev);

_quickSort(p->next, h); } }

// The main function to sort a linked list. It mainly calls _quickSort()

void quickSort(struct Node *head)

{ // Find last node

struct Node *h = lastNode(head);

// Call the recursive QuickSort

_quickSort(head, h);

4.

// Function to merge two linked lists

struct Node *merge(struct Node *first, struct Node *second)

{ // If first linked list is empty

if (!first)

return second;

// If second linked list is empty

if (!second)

return first;
// Pick the smaller value

if (first->data < second->data)

{ first->next = merge(first->next,second);

first->next->prev = first;

first->prev = NULL;

return first; }

else

{second->next = merge(first,second->next);

second->next->prev = second;

second->prev = NULL;

return second; } }

// Function to do merge sort

struct Node *mergeSort(struct Node *head)

{ if (!head || !head->next)

return head;

struct Node *second = split(head);

// Recur for left and right halves

head = mergeSort(head);

second = mergeSort(second);

// Merge the two sorted halves

return merge(head,second); }

5.
// Function to find pair whose sum equal to given value x.

void pairSum(struct Node *head, int x)

{ // Set two pointers, first to the beginning of DLL

// and second to the end of DLL.

struct Node *first = head;

struct Node *second = head;

while (second->next != NULL)

second = second->next;

// To track if we find a pair or not

bool found = false;

// The loop terminates when either of two pointers

// become NULL, or they cross each other (second->next

// == first), or they become same (first == second)

while (first != NULL && second != NULL &&

first != second && second->next != first)

{ // pair found

if ((first->data + second->data) == x)

{ found = true;

cout << "(" << first->data<< ", "

<< second->data << ")" << endl;

// move first in forward direction


first = first->next;

// move second in backward direction

second = second->prev; }

else

{ if ((first->data + second->data) < x)

first = first->next;

else

second = second->prev; } }

// if pair is not present

if (found == false)

cout << "No pair found"; }

6.

sortedInsert(head_ref, newNode)

if (head_ref == NULL)

head_ref = newNode

else if head_ref->data >= newNode->data

newNode->next = head_ref

newNode->next->prev = newNode

head_ref = newNode

else

Initialize current = head_ref

while (current->next != NULL and


current->next->data data)

current = current->next

newNode->next = current->next

if current->next != NULL

newNode->next->prev = newNode

current->next = newNode

newNode->prev = current

7.

/* Function to delete the node at the given position

in the doubly linked list */

void deleteNodeAtGivenPos(struct Node** head_ref, int n)

/* if list in NULL or invalid position is given */

if (*head_ref == NULL || n <= 0)

return;

struct Node* current = *head_ref;

int i;

/* traverse up to the node at position 'n' from

the beginning */

for (int i = 1; current != NULL && i < n; i++)

current = current->next;
/* if 'n' is greater than the number of nodes

in the doubly linked list */

if (current == NULL)

return;

/* delete the node pointed to by 'current' */

deleteNode(head_ref, current);

8.

// function to count triplets in a sorted doubly linked list

// whose sum is equal to a given value 'x'

int countTriplets(struct Node* head, int x)

{ struct Node* ptr, *ptr1, *ptr2;

int count = 0;

// unordered_map 'um' implemented as hash table

unordered_map<int, Node*> um;

// insert the <node data, node pointer> tuple in 'um'

for (ptr = head; ptr != NULL; ptr = ptr->next)

um[ptr->data] = ptr;

// generate all possible pairs

for (ptr1 = head; ptr1 != NULL; ptr1 = ptr1->next)


for (ptr2 = ptr1->next; ptr2 != NULL; ptr2 = ptr2->next) {

// p_sum - sum of elements in the current pair

int p_sum = ptr1->data + ptr2->data;

// if 'x-p_sum' is present in 'um' and either of the two nodes

// are not equal to the 'um[x-p_sum]' node

if (um.find(x - p_sum) != um.end() && um[x - p_sum] != ptr1

&& um[x - p_sum] != ptr2)

// increment count

count++; }

// required count of triplets

// division by 3 as each triplet is counted 3 times

return (count / 3); }

9.

removeDuplicates(head_ref, x)

if head_ref == NULL

return

Initialize current = head_ref

while current->next != NULL

if current->data == current->next->data

deleteNode(head_ref, current->next)

else
current = current->next

10.

delAllOccurOfGivenKey(head_ref, x)

if head_ref == NULL

return

Initialize current = head_ref

Declare next

while current != NULL

if current->data == x

next = current->next

deleteNode(head_ref, current)

current = next

else

current = current->next

11.

// function to remove duplicates from

// an unsorted doubly linked list

void removeDuplicates(struct Node** head_ref)

{ // if doubly linked list is empty

if ((*head_ref) == NULL)

return;

// unordered_set 'us' implemented as hash table

unordered_set<int> us;
struct Node* current = *head_ref, *next;

// traverse up to the end of the list

while (current != NULL) {

// if current data is seen before

if (us.find(current->data) != us.end()) {

// store pointer to the node next to

// 'current' node

next = current->next;

// delete the node pointed to by 'current'

deleteNode(head_ref, current);

// update 'current'

current = next; }

else {

// insert the current data in 'us'

us.insert(current->data);

// move to the next node

current = current->next; } } }

12.

// A simple recursive function to convert a given


// Binary tree to Doubly Linked List

// root --> Root of Binary Tree

// head_ref --> Pointer to head node of created

// doubly linked list

void BToDLL(Node* root, Node** head_ref)

{ // Base cases

if (root == NULL)

return;

// Recursively convert right subtree

BToDLL(root->right, head_ref);

// insert root into DLL

root->right = *head_ref;

// Change left pointer of previous head

if (*head_ref != NULL)

(*head_ref)->left = root;

// Change head of Doubly linked list

*head_ref = root;

// Recursively convert left subtree

BToDLL(root->left, head_ref); }

13.
// Partitions the list taking the last element as the pivot

struct Node *partition(struct Node *head, struct Node *end,

struct Node **newHead, struct Node **newEnd)

{ struct Node *pivot = end;

struct Node *prev = NULL, *cur = head, *tail = pivot;

// During partition, both the head and end of the list might change

// which is updated in the newHead and newEnd variables

while (cur != pivot)

{ if (cur->data < pivot->data)

{ // First node that has a value less than the pivot - becomes

// the new head

if ((*newHead) == NULL)

(*newHead) = cur;

prev = cur;

cur = cur->next; }

else // If cur node is greater than pivot

{ // Move cur node to next of tail, and change tail

if (prev)

prev->next = cur->next;

struct Node *tmp = cur->next;

cur->next = NULL;

tail->next = cur;

tail = cur;
cur = tmp; } }

// If the pivot data is the smallest element in the current list,

// pivot becomes the head

if ((*newHead) == NULL)

(*newHead) = pivot;

// Update newEnd to the current last node

(*newEnd) = tail;

// Return the pivot node

return pivot; }

//here the sorting happens exclusive of the end node

struct Node *quickSortRecur(struct Node *head, struct Node *end)

{ // base condition

if (!head || head == end)

return head;

Node *newHead = NULL, *newEnd = NULL;

// Partition the list, newHead and newEnd will be updated

// by the partition function

struct Node *pivot = partition(head, end, &newHead, &newEnd);


// If pivot is the smallest element - no need to recur for

// the left part.

if (newHead != pivot)

{ // Set the node before the pivot node as NULL

struct Node *tmp = newHead;

while (tmp->next != pivot)

tmp = tmp->next;

tmp->next = NULL;

// Recur for the list before pivot

newHead = quickSortRecur(newHead, tmp);

// Change next of last node of the left half to pivot

tmp = getTail(newHead);

tmp->next = pivot; }

// Recur for the list after the pivot element

pivot->next = quickSortRecur(pivot->next, newEnd);

return newHead; }

// The main function for quick sort. This is a wrapper over recursive

// function quickSortRecur()

void quickSort(struct Node **headRef)

{ (*headRef) = quickSortRecur(*headRef, getTail(*headRef));

return; }
14.

/* A[] --> Array to be sorted,

l --> Starting index,

h --> Ending index */

void quickSort(int A[], int l, int h)

{ if (l < h)

{ /* Partitioning index */

int p = partition(A, l, h);

quickSort(A, l, p - 1);

quickSort(A, p + 1, h); } }

15. ALGO:

MergeSort(headRef)

1) If head is NULL or there is only one element in the Linked List

then return.

2) Else divide the linked list into two halves.

FrontBackSplit(head, &a, &b); /* a and b are two halves */

3) Sort the two halves a and b.

MergeSort(a);

MergeSort(b);

4) Merge the sorted a and b (using SortedMerge() discussed here)

and update the head pointer using headRef.

*headRef = SortedMerge(a, b);

Vous aimerez peut-être aussi