您的位置:首页 > 其它

Linked List

2017-01-11 20:48 127 查看

Introduction:

Like arrays, Linked List is a linear data structure.

Unlike arrays, linked list elements are not stored at contiguous location; the elements are linked using pointers.

Why Linked List ?

The limitations of array:

1) The size of the arrays is fixed: So we must know the upper limit on the number of elements in advance. Also, generally, the allocated memory is equal to the upper limit irrespective of the usage.

2) Inserting a new element in an array of elements is expensive, because room has to be created for the new elements and to create room existing elements have to shifted.

Deletion is also expensive with arrays until unless some special techniques are used.

Advantages over Linked List:

1) Dynamic size

2) Ease of insertion/deletion

Drawbacks:

1) Random access is not allowed. We have to access elements sequentially starting from the first node. So we cannot do binary search with linked lists.

2) Extra memory space for a pointer is required with each element of the list.

3) Arrays have better cache locality that can make a pretty big difference in performance.

Representation in C:

A linked list is represented by a pointer to the first node of the linked list. The first node is called head. If the linked list is empty, then value of head is NULL.

Each node in a list consists of at least two parts:

1) data

2) pointer to the next node

In C, we can represent a node using structures. Below is an example of a linked list node with an integer data.

In Java, LinkedList can be represented as a class and a Node as a separate class. The LinkedList class contains a reference of Node class type.

singly linked list

node

// A linked list node
struct node
{
int data;
struct node *next;
};


traversal

// linked list traversal
void printList(struct node *head)
{
while(head)
{
printf("%d ", head -> data);
head = head -> next;
}
}


insert

at the front

after the given node

at the end

// insert node

// 1. at the front
/* we need the pointer of pointer head for we have to change the head pointer's pointing object,
* that is from prev_node to new_node;
*/
void push_front(struct node **head, int new_data)
{
// allocate node
struct node *new_node = (struct node *)malloc(sizeof(struct node));
if (!new_node) return ;

// put in the data
new_node -> data = new_data;

// if list is empty, head is new_node
if(!*head)
{
*head = new_node;
new_node -> next = NULL;
return ;
}

// make next of new node as head
new_node -> next = *head;

// move the head to point to the new node
*head = new_node;
}

// 2. after a given node
/* we don't need the pointer of the pointer pre_node
*for we don't have to change the pointer's pointing object;
*/
void push_mid(struct node *pre_node, int new_data)
{

// check if the given pre_node is NULL
if(!pre_node) return ;

// allocate node
struct node *new_node = (struct node *)malloc(sizeof(struct node));
if(!new_node) return ;

// put in the data
new_node -> data = new_data;

// make next of the new node as next of the prev_node
new_node -> next = pre_node -> next;

// move the next of the pre_node as new_node
pre_node -> next = new_node;
}

// 3. at the end
/* we need the pointer of the pointer head
* for we may change it when the new_node is first node
* This method can also be optimized to work in O(1) by keeping an extra pointer to tail of linked list/
*/
void push_end(struct node **head, int new_data)
{
// allocate new node
struct node *new_node = (struct node *)malloc(sizeof(struct node));
if(!new_node) return;

// put in the data
new_node -> data = new_data;

// the new_node is the last node,so its next is NULL
new_node -> next = NULL;

// if the linked list is NULL, then the new node is the head node
if (!*head)
{
*head = new_node;
return ;
}

// find the tail node
struct node *tail = *head;
while(tail -> next != NULL)
{
tail = tail -> next;
}

// change the node of the last node
tail -> next = new_node;
return ;
}


delete

delete a given node

delete a given position

// delete node

// delete a given key
void pop_key(struct node **head, int key)
{
struct node *temp = *head, *prev;

// if head itself is the key to be deleted, and then exit
if(temp && temp -> data == key)
{
*head = temp -> next;
free(temp);
return ;
}

// search for the data to be deleted
while(temp && temp -> data != key)
{
prev = temp;
temp = temp -> next;
}
prev -> next = temp -> next;

// If data was not present in the linked list
if(temp == NULL) return ;
free(temp);
}

// 2. delete a node at a given position
// pos starts from 0
void pop_pos(struct node **head, int pos)
{
struct node *temp = *head;

// if linked list is empty
if(!*head) return ;

// if head needs to be removed
if(!pos)
{
*head = temp -> next;
free(temp);
return ;
}

//find previous node of the node to be deleted
for (int i = 0; i < pos - 1 && temp != NULL ;i++)
{
temp = temp -> next;
}

// if position is more than numbers of nodes
if(!temp || !temp -> next) return ;

// node temp -> next is the node to be deleted
// nextn is the next node of the node to be deleted
struct node *nextn = temp -> next -> next;
free(temp -> next);
temp -> next = nextn;
}


[b]Remove Linked List Elements(LeetCode)[/b]

Remove all elements from a linked list of integers that have value val.

/**
* Definition for singly-linked list.
* struct ListNode {
*     int val;
*     struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val) {
int count = 0;
struct ListNode *p = NULL, *temp = NULL, *prev;
for (p = head; p != NULL; p = p -> next)
{
if(p -> val == val)
{
if(p == head)
{
temp = head;
head = head -> next;
}
else
{
temp = p;
prev -> next = p -> next;
}
free(temp);
}
else prev = p;
}
return head;
}


search

// search an given element in a Linked LIst , return true if the element is present.

// C90 does not support the boolean data type.
// C99 does include it with this include: #include <stdbool.h>
// or define ourselves : typedef enum { false, true } bool;

bool search_it(struct node *head, int x)
{
while(head && head -> data != x)
{
head = head -> next;
}
return (head == NULL) ? false : true;
}

bool search_re(struct node *head, int x)
{
if(!head) return false;
if(head -> data == x) return true;
return search_re(head -> next, x);
}


[b]Find n’th node from the end of a Linked List(geek)[/b]

1. 循环得到总结点数,再换成从前往后查找;

/* struct Node
{
int data;
Node* next;
}; */

/* Should return data of n'th node from the end of linked list */
int getNthFromLast(Node *head, int n)
{
// Your code here
int count = 0;
struct Node *temp = head;
while(temp)
{
count ++;
temp = temp -> next;
}
temp = head;
int n1 = count - n;
if(n1 < 0) return -1;
while(n1--)
{
temp = temp -> next;
}
return temp -> data;

}


2. 两个指针,第一个指向第一个位置,第二个指向第n个位置,第一和第二个指针同步往前遍历,第二个指针到底时第一个指针即为所求;

/* struct Node
{
int data;
Node* next;
}; */

/* Should return data of n'th node from the end of linked list */
int getNthFromLast(Node *head, int n)
{
// Your code here
struct Node *first = head;
struct Node *second = head;
while(--n)
{
if(!second -> next) return -1;
else second = second -> next;
}
while(second -> next)
{
second = second -> next;
first = first -> next;
}
return first -> data;
}


关于递归,如果是打印的话很简单,但是return的话不容易做;

swap

void swap(struct node **head, int x, int y)
{
// make sure x != y
if(x == y)
{
printf("the two given numbers are the same");
return ;
}
// at least two distinct node
if(!*head || !(*head) -> next)
{
printf("the list is empty, please use push_end to push some elements first");
return ;
}

// Search for X(keep track of prevX and currX)
struct node *prevX = NULL, *currX = *head ;
while(currX && currX -> data != x)
{
prevX = currX;
currX = currX -> next;
}

// Search for Y(keep track of prevY and currY)
struct node *prevY = NULL, *currY = *head;
while(currY && currY -> data != y)
{
prevY = currY;
currY = currY -> next;
}

// if X or Y is not present, return
if(!currX || !currY)
{
printf("X or Y is not present");
return ;
}

// change the previous pointer of currX and currY
if(prevX) prevX -> next = currY;
else *head = currY;

if(prevY) prevY -> next = currX;
else *head = currX;

// swap next pointer
struct node *temp = currY -> next;
currY -> next = currX -> next;
currX -> next = temp;
}


reverse

iterative :

void reverse_it(struct node **head)
{
if(!*head)
{
printf("the list is empty");
return ;
}
struct node *curr = (*head) -> next, *prev = *head, *latter = curr;
while(curr)
{
latter = curr -> next;
curr -> next = prev;
prev = curr;
curr = latter;
}
(*head) -> next = NULL;
*head = prev;
}


recursive:

void reverse_re(struct node** head)
{
if(!head) return ;
struct node *first = *head, *second = first -> next;
if(!second) return ;
reverse_re(&second);
// second will change, so we can't use second -> next = first;
first -> next -> next = first;
first -> next = NULL;
*head = second;
}

void reverse_re1(struct node *p, struct node **head)
{
if(!p -> next)
{
*head = p;
return ;
}
reverse_re1(p -> next, head);
struct node *q = p -> next;
q -> next = p;
p -> next = NULL;
}


main for test

int main()
{
// start with the empty list
struct node *head = NULL;
push_front(&head, 1);
push_end(&head, 3);
push_mid(head, 2);
printList(head);
puts("\nNow delete data 1");
pop_key(&head, 1);
printList(head);
puts("\nNow delete position 1");
pop_pos(&head, 1);
printList(head);
return 0;
}


Doubly Linked List

node

// A doubly list node
struct node
{
int data;
struct node *prev;
struct node *next;
};


insert

// add a node at the front
void push_front(struct node **head, int new_data)
{
// allocate node
struct node *new_node = malloc(sizeof(struct node));
if(!new_node) return ;

// put in the data
new_node -> data = new_data;

// next to head, prev to NULL
new_node -> next = *head;
new_node -> prev = NULL;

// head prev to new_node
if(*head) (*head) -> prev = new_node;

// head moves to new_node
*head = new_node;
}

//insert after a given node
void push_after(struct node *prev_node, int new_data)
{

// check if the given node is NULL
if(!prev_node) return ;

// allocate node
struct node *new_node = malloc(sizeof(struct node));
if(!new_node) return ;

// put in the data
new_node -> data = new_data;
new_node -> prev = prev_node;
new_node -> next = prev_node -> next;

prev_node -> next = new_node;
if(new_node -> next) new_node -> next -> prev = new_node;
}

void push_end(struct node **head, int new_data)
{
struct node *new_node = malloc(sizeof(struct node));
if(!new_node) return ;

new_node -> data = new_data;

new_node -> next = NULL;

if(!*head)
{
new_node -> prev = NULL;
*head = new_node;
return ;
}

while(*head -> next)
{
*head = (*head) -> next;
}
}


/* 未完待续 */
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  DS LinkedList