लिंक्ड सूची में पॉइंटर को इंगित करने के लिए
क्या कोई मुझे समझा सकता है कि इस कोड ने मुझे खाली सूची के परिणामस्वरूप क्यों दिया:
typedef struct str_node{
int data;
struct str_node *next;
}node;
void begin(node *head);
void display_list(node *head);
int main(){
node *head;
int i;
head = NULL;
for(i=0;i<5;i++) {
begin(head);
}
display_list(head);
return 0;
}
void begin(node *head){
node *new;
int value;
new = (node*) malloc(sizeof(node));
printf("Insert the element to add at the beginning of the list: ");
scanf("%d",&value);
new->data = value;
new->next = head;
head = new;
}
लेकिन अगर मैं सूचक को सूचक के साथ शुरुआत () फ़ंक्शन को बदल दूं तो यह मुझे सही सूची देता है?
void begin(node **head){
node *new;
int value;
new = (node*) malloc(sizeof(node));
printf("Insert the element to add at the beginning of the list: ");
scanf("%d",&value);
new->data = value;
new->next = *head;
*head = new;
}
क्या आप मुझे यह भी समझा सकते हैं कि जब मैं फ़ंक्शन के मुख्य नोड हेड से शुरू होता हूं तो मुझे इसे "और हेड" के रूप में पास करना होगा? और "सिर" के रूप में नहीं
जवाब
इस कोड स्निपेट में पहले कार्यक्रम में
head = NULL;
for(i=0;i<5;i++) {
begin(head);
}
पॉइंटर head
को begin
वैल्यू द्वारा फंक्शन में पास किया जाता है। यह head
मुख्य में घोषित पॉइंटर के मूल्य की एक प्रति बनाई गई है और फ़ंक्शन के समान नाम के साथ पैरामीटर को असाइन किया गया है
void begin(node *head);
इसलिए फ़ंक्शन के भीतर यह पैरामीटर है head
जो शुरू head
में बदले जाने वाले मूल पॉइंटर की एक प्रति रखता है। मूल पॉइंटर head
जिसका मान पैरामीटर को सौंपा गया था उसे बदला नहीं जा रहा है।
मुख्य रूप से घोषित मूल पॉइंटर हेड को बदलने के लिए आपको इसे अप्रत्यक्ष रूप से पॉइंटर हेड के लिए एक सूचक के माध्यम से फ़ंक्शन में पास करना होगा क्योंकि यह दूसरे प्रोग्राम में किया जाता है।
इसलिए समारोह को घोषित किया जाना चाहिए
void begin(node **head);
और आपको सूचक को अप्रत्यक्ष रूप से एक सूचक के माध्यम से इसे पास करना होगा
begin( &head );
इस मामले में, पास किए गए पॉइंटर को डीफ्रेंसिंग करने से फ़ंक्शन को मुख्य में घोषित मूल पॉइंटर हेड तक सीधी पहुंच मिलेगी और इसे बदल सकते हैं (इसके मूल्य की एक प्रति नहीं है क्योंकि यह पहले फ़ंक्शन परिभाषा में जगह लेता है)
new->next = *head;
*head = new;
इसे और स्पष्ट करने के लिए इस सरल प्रदर्शनकारी कार्यक्रम पर विचार करें।
#include <stdio.h>
typedef int T;
void f( T t )
{
t = 10;
}
int main(void)
{
T t = 0;
printf( "Before calling f t is equal to %d\n", t );
f( t );
printf( "After calling f t is equal to %d\n", t );
return 0;
}
इसका आउटपुट है
Before calling f t is equal to 0
After calling f t is equal to 0
चूंकि फ़ंक्शन च पास किए गए तर्क के मूल्य की एक प्रति से संबंधित है, t
मुख्य में घोषित चर का मूल्य नहीं बदला गया था।
तो आपको t
पॉइंटर के माध्यम से संदर्भ द्वारा मूल चर को पास करने की आवश्यकता है
#include <stdio.h>
typedef int T;
void f( T *t )
{
*t = 10;
}
int main(void)
{
T t = 0;
printf( "Before calling f t is equal to %d\n", t );
f( &t );
printf( "After calling f t is equal to %d\n", t );
return 0;
}
अब प्रोग्राम आउटपुट है
Before calling f t is equal to 0
After calling f t is equal to 10
इन प्रदर्शनकारी कार्यक्रमों में नाम T
का उपयोग प्रकार के लिए एक उपनाम के रूप में किया जाता है int
और मुख्य रूप से ऑब्जेक्ट t
में यह प्रकार होता है।
चलिए अब मान लेते हैं कि T नाम टाइप * के लिए एक उपनाम है।
typedef int * T;
इस मामले में उदाहरण के लिए मुख्य रूप में एक घोषणा
T t = NULL;
इसका मतलब है कि चर t
में सूचक प्रकार है int *
। इसके बराबर है
int * t = NULL;
तो इसे एक फ़ंक्शन को पास करने के लिए जिसे मूल चर को बदलना होगा, हमें इसे संदर्भ द्वारा पास करना होगा
f( &t );
इसका मतलब है कि संबंधित फ़ंक्शन के पास घोषित पैरामीटर प्रकार होगा
void f( T *t );
लेकिन जैसा कि इसके T
लिए एक उपनाम है, int *
इसका मतलब है कि फ़ंक्शन के प्रकार का एक पैरामीटर है int **
।
void f( int * *t );
क्योंकि head
(प्रभावी रूप से) एक स्थानीय वैरिएबल है, इसलिए इसे बदलने से फ़ंक्शन के बाहर कोई प्रभाव नहीं पड़ता है, जबकि *head
परिवर्तन जो head
इंगित करता है, और इस प्रकार करता है।
यदि आप एक फ़ंक्शन चाहते थे int
कि एक चर ( मान) में मान को बदलने में सक्षम हो x
, तो आप इसे एक पॉइंटर को x
पास करेंगे, जिसमें टाइप int*
होगा और आपको पॉइंटर का x
उपयोग करके प्राप्त होगा &x
। वही रखती है चाहे कोई भी प्रकार x
हो।
घोषणा करने से थोड़ा भ्रम हो सकता है
node *head;
के बजाय
node* head;
आप घोषित कर रहे हैं head
। head
चर है और यह एक सूचक है। यह एक नोड नहीं है। यह भी ध्यान दें कि एक नोड एक लिंक्ड सूची नहीं है: एक लिंक्ड सूची एक नोड का एक संग्रह है और संभवतया एक उपयोगी कार्यान्वयन के लिए कुछ और है। इस पर अधिक बाद में अंत में।
सच है कि आप में है main()
की घोषणा की head
है, बस एक node*
। नोड स्वयं भी अभी तक मौजूद नहीं है। आप घोषित begin()
रूप में
void begin(node *head);
और मुझे लगता है कि आप इसे और अधिक स्पष्ट रूप से देखेंगे
void begin(node* parameter);
parameter
है node*
।
अंदर begin()
आपको पॉइंटर की एक कॉपी मिलती है और पॉइंटर बदलने से ओरिजनल पॉइंटर नहीं बदलेगा main()
। आपके मामले में यह main()
हमेशा के लिए इंगित करेगा NULL
।
क्या मायने रखता है कि एक सूचक किसी भी चर की तरह है: एक सूचक का एक पता है। और एक सामग्री। जब आप मूल्य से गुजरते हैं, तो जैसे आपने किया, सूचक के begin()
साथ शुरू होता है NULL
, जिस मूल्य से आया था main()
। लेकिन उनके बीच का बंधन कॉल को समाप्त करता है: प्रारंभिक मूल्य।
जब आप एक सूचक को पास begin()
करते हैं, तो ऑपरेटर के पते का उपयोग करते हुए और &head
चीजों को लिखते हुए बदल जाता है: आप ऑपरेटर के '*'
अर्थ का उपयोग करके इसे बदल देंगे, जिससे आप उस पते को बदल देंगे, जिससे यह बदल जाएगा main()
। के बाद से head
किया गया है node*
यह के सूचक के रूप घोषित किया जाएगाnode**
लेकिन begin()
लिंक की गई सूची के उपयोग की घोषणा को बदलने पर विचार करें:
node* begin(node* node);
तर्क यह है कि नोड डालने से सूची का प्रमुख बदल सकता है, इसलिए आप नया पता वापस करते हैं, जैसे कि
node* _insert_begin(int value, node* pNode)
{
node* new = (node*)malloc(sizeof(node));
new->data = value;
new->next = pNode;
return new;
}
यह लिखने का एक सामान्य तरीका है। एक और उपयोग करना है node**
।
जिस तरह से मैं यहां बता रहा हूं, कोई भी ऑपरेशन जो सूची के प्रमुख को बदल सकता है
- नया सिर लौटाओ
- प्राप्त करें और सिर के पॉइंटर को पॉइंटर अपडेट करें
सूची की शुरुआत में सम्मिलित होने वाले इस कोड को फिर से देखें:
node* _insert_begin(int value, node* pNode)
{ // insert 'value' at the start of the list
node* new = (node*)malloc(sizeof(node));
(*new).data = value;
new->next = pNode;
return new;
}
लौटने new
आप मिल head
अपडेट किया गया। और आप में लिख सकते हैंmain()
node* another = NULL;
display_list(another);
// inserts 5 to 0 at the beginning
for (int i = 5; i >= 0; i -= 1)
another = _insert_begin(i, another);
printf("inserted 5..0 at the beginning\n");
display_list(another);
लाइन पर ध्यान दें another = _insert_begin(i, another);
और आप देखें कि पॉइंटर कैसे main()
अपडेट होता है।
यह आउटपुट है
empty list
inserted 5..0 at the beginning
0 1 2 3 4
5
list has 6 elements
इसके कार्यान्वयन के उपयोग से display_list()
, प्रति पंक्ति 5 मान प्रिंट करता है:
int display_list(node* p)
{
if (p == NULL)
{
printf("empty list\n");
return 0;
};
int count = 0;
// not empty
do
{
printf("%8d ", p->data);
count++;
if (count % 5 == 0) printf("\n");
p = p->next;
} while (p != NULL);
if (count % 5 != 0) printf("\n");
printf("list has %d elements\n", count);
return count;
};
एक और उदाहरण: अंत में सम्मिलित करना
ध्यान दें कि अंत में डालने से सिर भी बदल सकता है, इस मामले में कि सूची खाली है, इसलिए हमें अभी भी सिर का पता वापस करना होगा
node* _insert_end(int value, node* pNode)
{ // insert value at the end of the list
node* new = (node*)malloc(sizeof(node));
new->data = value;
new->next = NULL;
if (pNode == NULL) return new;
node* p = pNode;
while (p->next != NULL) p = p->next;
p->next = new;
return pNode;
}
एक और उपयोग: आरोही क्रम में सम्मिलित करना
ज़रूर, आरोही क्रम में डालने से भी सिर बदल सकता है, जैसे कि
node* _insert_ordered(int value, node* pNode)
{ // insert value at ascending order in the list
node* new = (node*)malloc(sizeof(node));
new->data = value;
new->next = NULL;
if (pNode == NULL) return new;
node* p = pNode;
node* prev = NULL; // previous node: list if forward only
while (p->next != NULL)
{
if (new->data < p->data)
{
// insert before first greater than value
if (prev == NULL)
{
// new head
new->next = p;
return new;
}; // if()
prev->next = new;
new->next = p;
return pNode; // no change in head
};
prev = p; p = p->next; // updates pointers
}; // while()
// we are at the end: new will be the last?
if (new->data < p->data)
{
if (prev == NULL)
pNode = new;
else
prev->next = new;
new->next = p;
}
else
{
p->next = new;
};
return pNode;
} // _insert_ordered()
सूची हटाना
node*
हेड पॉइंटर को अमान्य करने के लिए एक सूची को भी हटा दें । यह सामान्य है। जैसा कि आपको इसके मैकेनिक की आदत है, यह सुनिश्चित करता है कि एक अमान्य पॉइंटर आसपास नहीं रहता है।
ध्यान दें कि यह तर्क सहकारी है: आपको हर कॉल पर हेड पॉइंटर को वापस असाइन करना होगा जो सिर को बदल सकता है
node* delete_list(node* H)
{
if (H == NULL) return NULL;
if (H->next == NULL)
{ // single node
free(H);
return NULL;
};
// more than one node
do
{ node* p = H->next;
free(H);
H = p;
} while (H != NULL);
return NULL;
};
एक चल रहा कार्यक्रम
उदाहरण कार्यक्रम का आउटपुट
empty list
inserted 5..0 at the beginning
0 1 2 3 4
5
list has 6 elements
inserted 6 to 10 at the end
0 1 2 3 4
5 6 7 8 9
10
list has 11 elements
inserted 0 to 10, ordered
0 0 1 1 2
2 3 3 4 4
5 5 6 6 7
7 8 8 9 9
10 10
list has 22 elements
inserted -1 to -10, ordered
-10 -9 -8 -7 -6
-5 -4 -3 -2 -1
0 0 1 1 2
2 3 3 4 4
5 5 6 6 7
7 8 8 9 9
10 10
list has 32 elements
inserted 11 to 20, ordered
-10 -9 -8 -7 -6
-5 -4 -3 -2 -1
0 0 1 1 2
2 3 3 4 4
5 5 6 6 7
7 8 8 9 9
10 10 11 12 13
14 15 16 17 18
19 20
list has 42 elements
about to delete list
empty list
उदाहरण C प्रोग्राम
#include <stdio.h>
#include <stdlib.h>
typedef struct str_node
{
int data;
struct str_node* next;
} node;
void begin(node* pNode);
node* delete_list(node*);
int display_list(node*);
node* _insert_begin(int, node*);
node* _insert_end(int, node*);
node* _insert_ordered(int, node*);
int main()
{
node* another = NULL;
display_list(another);
// insert 5 to 0 at the beginning
for (int i = 5; i >= 0; i -= 1)
another = _insert_begin(i, another);
printf("inserted 5..0 at the beginning\n");
display_list(another);
// insert 6 to 10 at the end
for (int i = 6; i <= 10; i += 1)
another = _insert_end(i, another);
printf("inserted 6 to 10 at the end\n");
display_list(another);
// insert 0 to 10 ordered
for (int i = 0; i <=10; i += 1)
another = _insert_ordered(i, another);
printf("inserted 0 to 10, ordered\n");
display_list(another);
// insert -1 to -10 ordered
for (int i = -1; i >= -10; i -= 1)
another = _insert_ordered(i, another);
printf("inserted -1 to -10, ordered\n");
display_list(another);
// insert 11 to 20 ordered
for (int i = 11; i <= 20; i += 1)
another = _insert_ordered(i, another);
printf("inserted 11 to 20, ordered\n");
display_list(another);
printf("about to delete list\n");
another = delete_list(another);
display_list(another);
return 0;
}
node* delete_list(node* H)
{
if (H == NULL) return NULL;
if (H->next == NULL)
{ // single node
free(H);
return NULL;
};
// more than one node
do
{ node* p = H->next;
free(H);
H = p;
} while (H != NULL);
return NULL;
};
node* _insert_begin(int value, node* pNode)
{ // insert 'value' at the start of the list
node* new = (node*)malloc(sizeof(node));
(*new).data = value;
new->next = pNode;
return new;
}
node* _insert_end(int value, node* pNode)
{ // insert value at the end of the list
node* new = (node*)malloc(sizeof(node));
new->data = value;
new->next = NULL;
if (pNode == NULL) return new;
node* p = pNode;
while (p->next != NULL) p = p->next;
p->next = new;
return pNode;
}
node* _insert_ordered(int value, node* pNode)
{ // insert value at ascending order in the list
node* new = (node*)malloc(sizeof(node));
new->data = value;
new->next = NULL;
if (pNode == NULL) return new;
node* p = pNode;
node* prev = NULL; // previous node: list if forward only
while (p->next != NULL)
{
if (new->data < p->data)
{
// insert before first greater than value
if (prev == NULL)
{
// new head
new->next = p;
return new;
}; // if()
prev->next = new;
new->next = p;
return pNode; // no change in head
};
prev = p; p = p->next; // updates pointers
}; // while()
// we are at the end: new will be the last?
if (new->data < p->data)
{
if (prev == NULL)
pNode = new;
else
prev->next = new;
new->next = p;
}
else
{
p->next = new;
};
return pNode;
} // _insert_ordered()
int display_list(node* p)
{
if (p == NULL)
{
printf("empty list\n");
return 0;
};
int count = 0;
// not empty
do
{
printf("%8d ", p->data);
count++;
if (count % 5 == 0) printf("\n");
p = p->next;
} while (p != NULL);
if (count % 5 != 0) printf("\n");
printf("list has %d elements\n", count);
return count;
};
यकीनन अधिक उपयोगी लिंक्ड सूची संरचना
निम्नलिखित को धयान मे रखते हुए
struct no
{
void* item;
struct no* next;
struct no* prev;
}; // no
typedef struct no Node;
typedef struct
{ // example, more flexible
char* name;
unsigned size;
unsigned capacity;
Node* head;
Node* tail;
} Linked_list;
इस तरह एक लिंक की गई सूची को नोड्स के एक कंटेनर के रूप में परिभाषित किया गया है।
- यह एक वैकल्पिक भी है
name
। size
हमेशा उपलब्ध है और अप टू डेट है- एक आकार सीमा के रूप में लागू किया जा सकता है
capacity
- अंत में डालें और शुरुआत में आपको अन्य सभी नोड्स का पालन करने की आवश्यकता नहीं है , क्योंकि सूची सिर और पूंछ दोनों को संकेत देती है।
- नोड में अगले और पिछले नोड्स की ओर संकेत होता है इसलिए कुछ डेटा जैसे कि प्लेलिस्ट या संग्रह जैसे कि अधिक आसानी से प्रसारित किया जा सकता है।
- एक कार्यक्रम में किसी भी संख्या की सूची हो सकती है क्योंकि हर एक इस मेटाडेटा को इनकैप्सुलेट करता है।
- एक सूची में कुछ भी हो सकता है क्योंकि डेटा शून्य करने के लिए एक संकेतक है,
void*
- खाली () या आकार () जैसे कार्यों को आसानी से लागू किया जा सकता है
- सभी फ़ंक्शन सूची में पॉइंटर का उपयोग करते हैं
Linked_list ll_one;
Linked_list many_ll[20];
Linked_list* pLL = &ll_one;
के बारे में:
void begin(node *head){
बदल रहा है head
केवल कॉल स्टैक 'सिर', क्या जरूरत है बदल जाता है जहां फोन करने वाले का समारोह अंक में 'सिर' के लिए परिवर्तन करने के लिए है। ऐसा करने के लिए, कॉलर को 'हेड' का पता देना होगा। तथ्य यह है कि 'हेड', अपने आप में एक पॉइंटर होता है जो इस बात की स्पष्टता के साथ मदद नहीं करता है कि क्या किया जाना चाहिए,