Basic Link List in C

ผมอยากเขียน blog แต่ไม่รู้ว่าจะเขียนอะไรดีพอดีกำลังเรียนมหาลัยอยู่ใกล้สอบแล้วเลยอยากเขียนบทความสอนเกียวกับ link list ให้เพื่อนได้อ่าน เนื้อหาไม่ลึก และ อาจมีข้อผิดพลาดบ้างนะครับ

Link list คืออะไร

Link list จริงๆแล้วก็คล้ายๆ array ซึงมีข้อแตกต่างกันอยู่เล็กน้อย

Array ในแต่ละกล่องจะเก็บแค่ค่าที่เราใส่ลงไป

Link list นั้นจะเก็บ address ขอช่องที่ติดกันอยู่ด้วย สามารถมีทั้งแบบ ทางเดียวและแบบไปกลับได้

อธิบายเพิ่มเติมเพื่อให้เข้าใจภาพได้ง่ายขึ้น

ตัวเลขบนกล่องคือ address(ค่าตำแหน่งที่เก็บข้อมูลบน memory)
กล่อง คือ struct ที่เก็บตัวแปรสองชนิด int , pointer(ตัวแปรที่เก็บค่า address)
ค่า address ที่แสดงเป็นเพียงค่าสมมุติ

ทำไมมี array แล้วต้องใช้ link list

การที่เราเก็บข้อมูลเป็น array ในบางเหตุการที่เราต้องการที่จะแทนข้อมูลลงไปใน array นั้นเราต้องทำการขยับข้อมูลที่มีอยู่ให้ถอยหลังออกไปทำให้เราต้องเสียเวลาเขียน loop เพื่อขยับข้อมูลใน array แต่ link list สามารถแก้ปัญหานี้ได้เพราะการสามารถนำข้อมูลใหม่เข้ามาแทรกได้โดยไม่จำเป็นต้องขยับข้อมูลที่มีอยู่เลย เพียงแค่เปลียน pointer เท่านั้น

จะเห็นได้ว่าการแทรกข้อมูลของ link list นั้นเพียงแค่เป็นการแก้ไข pointer ให้ไปยังกล่องใหม่แล้วให้กล่องใหม่ ชี้ไปยังกล่องถัดไป

นอกจากนี้เรายังสามารถนำ link list ไปใช้ทำ stack หรือ queue

Link list ทางเดียว กับสองทางต่างกันยังไง

Link list ทางเดียว

นั้นเราจะไม่สามารถเรียกข้อมูลก่อนหน้าได้เนื่องจากเรามีเพียง pointer ที่ชี้ไปยังกล่องถัดไปเท่านั้น ทำให้ถ้าต้องการข้อมูลก่อนหน้าจำเป็นต้องไปไล่จากหัวใหม่เสมอ

Link list สองทาง

สามารถเรียกข้อมูลก่อนหน้าได้เพราะในตัวกล่องมีทั้ง pointer ที่ชี้ทั้งกล่องถัดไปและกล่องก่อนหน้านั้นเอง

เราก็ได้รู้จัก link list กับคร่าวๆแล้วก็มาลองทำ link list กับดูเลยดีกว่า

สร้างกล่องเก็บ

กล่องที่เก็บข้อมูลจะเรียกว่า node ซึ่งเราจะใช้ struct สร้างขึ้นมา

Struct ชื่อ node เก็บ value(ข้อมูลเป็นตัวเลข) กับ nextnode(เป็น pointer ที่ไว้ชี้ไป node ถัดไป)

สร้าง function

Function สร้าง กล่อง

เราจะสร้างฟังชั้นที่จะนำข้อมูลมาใส่ node และเชื่อม node เข้าด้วยกัน

เริ่มจากสร้าง node ขึ้นมา(10–12)บรรทัดที่13เซ็คว่ามีnodeหรือไม่ถ้าไม่มีก็ให้ใช้nodeที่สร้างขึ้นมาเลยแต่ถ้ามี node อยู่แล้วให้หากล่องสุดท้ายแล้วให้ pointer ชี้มายัง node ที่สร้างใหม่

Function print

การแสดงข้อมูลที่เรามีอยู่นั้นสามารถทำได้โดยเริ่มจากหัวแล้วขยับไปยัง node ต่อไปด้วย pointer ที่เก็บไว้

Function delete

เราสามารถลบ node ที่อยู่ภายใน link list ได้โดยเปลียน pointer ให้ข้ามไป node ถัดไปเลย แต่ในการลบนั้นมีหลายกรณีซึ่งต้องใช้วิธีในการลบที่แตกต่างกัน

มีสองกรณีคือตัวที่จะลบนั้นเป็นหัวของ link list กับ เป็นตัวอื่นที่ไม่ใช่หัว

ในกรณีที่ 1 เราจำเป็นต้องแก้ pointer ของ head ที่เข้ามาให้เป็น node ถัดไป อีกกรณีเราจะแก้ไขแค่ address ของ node ให้ชี้ข้าม node ที่เราจะลบไป

Function insert

ใน link list เราสามารถแทรงข้อมูลลงไปได้โดยแค่เปลียน pointer เท่านั้น

ตัวอย่างจะเป็นการแทรงข้อมูลให้มีค่าเรียงกันจากมากไปน้อย ซึ่งการที่เราเอาตัวเลขไปแทรกเพื่อเรื่องลำดับมีชื่อเรียกการจัดเรียงนี้ว่า insertion sort

การแทรงที่หัวของ link list จะต้องแยกกรณีไปเหมือน การ delete node

เราจะนำ link list ทางเดียวนี้มาทำเป็น stack และ queue กันแต่ก่อนอื่นเราต้องเข้าใจก่อนว่าสองอย่างนี้มันคืออะไร

Stack

เข้าหลังออกก่อน

function push นั้นเหมือนกัน createnode ของ link list ปกติ

function pop เราจะขยับไป node สุดท้ายแล้วแสดงค่าออกมา และให้ node ก่อนหน้าชี้ไป NULL แทน

Queue

เข้าก่อนออกก่อน

เราสามารถทำคล้ายๆ stack ได้เลยเพียงแค่ต้องเราออกข้อมูลออกให้เอาจากหัวออกก่อน


หากยังใช้งาน pointer ยังไม่ค่อยคล่องเท่าไหร่ลองอ่าน บทความเรื่อง pointer ดูครับ


Code ทั้งหมดที่ใช้

#include "stdio.h"
#include "stdlib.h"
typedef struct node{
int value;
struct node *nextnode;
}NODE;
void createnode(NODE **head,int value){
NODE *newnode,*tmp=*head;
newnode =(NODE*)malloc(sizeof(NODE));
newnode->value=value;
newnode->nextnode=NULL;
if(*head==NULL){
*head=newnode;
}else{
while(tmp->nextnode!=NULL)tmp=tmp->nextnode;
tmp->nextnode=newnode;
}
}
void printlist(NODE **head){
NODE *tmp=*head;
while(tmp!=NULL){
printf("%d->",tmp->value);
tmp=tmp->nextnode;
}
printf("\n");
}
void deletenode(NODE **head,int value){
NODE *tmp=*head;
if (*head!=NULL)
{
if(tmp->value==value){
(*head)=tmp->nextnode;
}else if(tmp->nextnode!=NULL){
while(tmp->nextnode!=NULL){
if(tmp->nextnode->value==value){
tmp->nextnode=tmp->nextnode->nextnode;
break;
}
tmp=tmp->nextnode;
}
}else{
printf("No match\n");
}
}else{
printf("link list empty\n");
}
}
void pop(NODE **head){
NODE *tmp=*head;
if(*head!=NULL){
if((*head)->nextnode!=NULL){
while(tmp->nextnode->nextnode!=NULL)tmp=tmp->nextnode;
printf("Pop :%d\n",tmp->nextnode->value);
tmp->nextnode=NULL;
}else{
printf("Pop :%d\n",(*head)->value);
*head=NULL;
}
}
}
void dequeue(NODE **head){
if(*head!=NULL){
printf("Dequeue %d\n",(*head)->value);
*head=(*head)->nextnode;
}
}
void insertnode(NODE **head,int value){
NODE *newnode,*tmp=*head;
newnode =(NODE*)malloc(sizeof(NODE));
newnode->value=value;
newnode->nextnode=NULL;
if(tmp!=NULL){
if(value>(*head)->value){
if(tmp->nextnode!=NULL){
while(tmp->nextnode->value<value)tmp=tmp->nextnode;
newnode->nextnode=tmp->nextnode;
tmp->nextnode=newnode;
if(tmp->nextnode==NULL)break;
}else{
tmp->nextnode=newnode;
}
}else{
newnode->nextnode=*head;
(*head)=newnode;
}
}else{
*head=newnode;
}
}
int main(int argc, char const *argv[])
{
NODE *head=NULL;
createnode(&head,50);
printlist(&head);
insertnode(&head,55);
insertnode(&head,65);
insertnode(&head,10);
printlist(&head);
pop(&head);
printlist(&head);
dequeue(&head);
printlist(&head);
dequeue(&head);
dequeue(&head);
dequeue(&head);
return 0;
}
void createnode(NODE **head,int value){
NODE *newnode;
newnode =(NODE*)malloc(sizeof(NODE));
newnode->value=value;
newnode->nextnode=NULL;
if(*head==NULL){
*head=newnode;
}else{
while((*head)->nextnode!=NULL)(*head)=(*head)->nextnode;
(*head)->nextnode=newnode;
}
}
Like what you read? Give Pongsatorn Manusopit a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.