天天看點

雙向連結清單的基本常用操作(建立、初始化、插入、删除、連結清單長度、查找指定元素的位置、連結清單的銷毀) c語言 資料結構 超詳細~~

/本程式中包含對雙向連結清單的::建立、初始化、插入、删除、連結清單長度、查找指定元素的位置以及雙向連結清單的銷毀/

#include<stdio.h>

#include<stdlib.h>

typedef int Elemtype;

typedef struct linknode

{

Elemtype data;

struct linknode* next;

}Linknode,Linklist;

//建立循環連結清單

Linknode create()

{

Linklist head = (Linklist)malloc(sizeof(Linknode));

if (!head)

{

printf(“配置設定記憶體空間失敗\n”);

return 0;

}

head->next = head;

return head;

}

//初始化循環連結清單(頭插法)(本質上是尾插法,但是每次都将最後一個結點

//作為第一個結點,就相當于頭插法)

void initnode(Linknode* head)

{

int elem;

Linknode* target,p;

while (1)

{

printf(“請輸入資料elem”);

scanf_s("%d", &elem);

if (elem == 0)

{/當我們輸入0的時候,就代表資料已經輸入完成了,就要通過break退出循環了/

printf(“輸入完成\n”);

break;

}

for (target = head->next; target != head; target = target->next);

/上面for循環的作用是找到雙向連結清單 的最後一個結點,那我們為什麼要找該雙向連結清單的最後一個結點呢?因為我們想要通過尾插法的形式進行連結清單的插入,并且當循環結束之後target就指向了雙向連結清單中的最後一個結點了/

p = (Linknode)malloc(sizeof(Linknode));

/為插入的結點申請空間/

if (!p)

{/如果p等于NULL,那麼申請記憶體空間失敗,那麼程式就應該傳回,注意直接用return傳回就可以了/

printf(“記憶體空間配置設定失敗\n”);

return;

}

/如果記憶體申請成功,就将剛剛輸入的elem的值指派給剛剛申請記憶體空間的結點,準備插入/

p->data = elem;

Linknode* headnode = target->next;

//通過周遊得到的target已經是循環周遊的最後一個結點了,那麼target->next就是該雙向連結清單中頭指針的位址

p->next = headnode;

/這句話可以和上一行的代碼一次性的寫成p->next=target-next,直接省略掉了headnode的步驟)

并且最後幾行代碼的含義就是先将剛剛準備插入的結點的next的指針指向頭指針,然後再将原先連結清單的最後一個結點指向剛剛加入的結點/

target->next = p;

/注意p->next=target-next和 target->next = p這兩句代碼就不能交換;因為如果交換了的話, target->next = p,p->next=target-next=p,那麼p->next就會等于p,而p->next在雙向連結清單中應該指向頭指針,因為它已經為最後一個元素了/

}

}

//循環連結清單的插入資料

void insertnode(Linknode* head, Elemtype x, int i)

{

//在位置i插入資料元素為x的結點

int j = 0;

Linknode* p = head,q;

for (j = 0; p->next != head && j < i-1; j++)

{/注意for循環中j<i-1就結束的原因是:

我們為了找到插入位置的前一個位置,因為我們需要用到插入位置的前一個位置的指針,需要将該指針的位址進行一個修改,從指向原來的結點到指向新插入的結點/

/現在我們來分析為什麼是j等于i-1就結束了::

因為剛開始p結點是指向頭節點的,并且 j剛開始也初始化為0,是以當p指向第i-1個結點時,這個結點是我們需要的結點,循環就應該結束,這時j等于i-1,是以當j<i-1的時候,都可以一個一個往下找,當j=i-1的時候,循環就應該結束,即此時p已經指向了第i-1個結點了/

p = p->next;

}

/注意該for循環結束是已經找到了第i-1個結點p了/

if (p->next != head)

{//找到了合理的插入的位置

//并且p為插入位置的前一個結點

/那為什麼插入位置合理的位置的條件是p->next != head呢??現在我們來分析::

由于該連結清單是一個雙向連結清單,p為待插入結點的上一個結點,如果p->next即p的下一個結點如果不存在的話,那麼就不可能在這個位置進行插入了,即插入失敗!!那麼說明時候為p的下一個結點不存在呢??就是p->next等于head,因為該連結清單是雙向連結清單,不是單連結清單,是以它的下一個結點不存在的判斷條件不是p->next!=NULL/

q = (Linknode)malloc(sizeof(Linknode));

/如果插入位置合理的話,就為該結點申請記憶體空間/

if (!q)

{

printf(“配置設定記憶體空間失敗\n”);

return;

/如果申請記憶體空間不成功,那麼就傳回,空即return掉/

}

q->data = x;/申請記憶體空間成功,那麼就将值x賦給新增加的結點的data域,再将該節點插入即可/

q->next = p->next;

p->next = q;

printf("%d已經插入成功\n", x);

/注意插入應該從後往前插入,因為如果從前往後插入的話,即先執行p->next=q的話,那麼p結點原先的下一個結點的指針就已經找不到了,就不能完成插入的相關操作,是以要先執行q->next=p->next;在執行p->next=q;如果先執行p->next=q的話,記得要先将p->next賦給一個變量/

}

else

{

printf(“插入失敗\n”);

}

}

//循環連結清單删除資料

void deletenode(Linknode* head, int i)

{

//删除位置為i的結點

int j;

Linknode* p = head,target;

for (j = 1; p->next!=head&&j < i; j++)

{//該for循環的目的是找到删除結點的上一個結點p

p = p->next;/必須要找到插入位置的前一個結點,因為你一旦找到了準備删除的結點,就找不到該節點的前驅結點了,就無法完成删除的相關操作了/

}

if (p->next != head)//找到了合理的删除的位置

{

target = p->next;

int elem = target->data;

p->next = target->next;

free(target);

printf("%d已經删除成功\n", elem);

}

else

{

printf(“删除失敗\n”);

}

}

//統計循環連結清單的長度

void calculate(Linknode head)

{

Linknode* p = head;//将雙向連結清單的頭指針賦給一個指針變量p,因為我們不可以随意對原先雙向連結清單的頭指針進行随意的改動*/

int count = 0;//電腦

while (p->next!= head)

{/當p->next指向頭指針的時候,雙向連結清單也就所有的元素都周遊一遍了/

count++;

p = p->next;

}

printf(“該連結清單的長度為%d\n”, count);

}

//銷毀循環連結清單

void destorynode(Linknode* head)

{

Linknode* p=head->next, * q;

while (p!= head)

{

q = p;

p = p->next;

free(q);

q = NULL;

}

head = NULL;

printf(“雙向連結清單已經銷毀完畢\n”);

}

//查找雙向連結清單中指定資料的位置

void searchnode(Linknode* head, Elemtype x)

{

Linknode* p = head;

int count = 0;//計數器

for (; p!= head && p->data != x; p = p->next,count++);

/該for循環的意思是在雙向連結清單内如果找到有結點的值等于x的,就退出循環;

是以我們如果在連結清單中找到了某個結點的值是等于x的,那麼p一定不等于head;反之如果我們沒有找到,那麼p一定是等于head的,意思是一直到最後一個結點都沒有找到,是以我們可以通過該判斷條件來判斷是否找到了指定了元素,若找到了指定的元素,就傳回它的位置,該count就是用來存儲該指定的元素在雙向連結清單的位置的/

if (p != head)

{

printf(“找到了,位置為%d\n”, count);

}

else

{

printf(“沒有找到\n”);

}

}

void print(Linknode* head)

{

Linknode* p = head->next;

/注意列印是從第一個有資料的結點開始,是以應該是head->next開始/

while (p != head)

{/一直列印到最後一個結點結束/

printf("%d\t", p->data);

p = p->next;

}

}

void test01()

{

int choice=0;

Linknode*L=NULL;

L = create();

initnode(L);

print(L);

printf("\n");

deletenode(L, 2);

print(L);

printf("\n");

insertnode(L, 100, 2);

print(L);

printf("\n");

deletenode(L, 1);

print(L);

printf("\n");

calculate(L);

printf("\n");

destorynode(L);

printf("\n");

}

int main(void)

{

test01();

system(“pause”);

return 0;

}

雙向連結清單的基本常用操作(建立、初始化、插入、删除、連結清單長度、查找指定元素的位置、連結清單的銷毀) c語言 資料結構 超詳細~~

代碼運作結果如圖所示

繼續閱讀