什么是鏈表?
鏈表其實就是一種數據結構,所謂的數據結構就是數據存放的思想。
數組、鏈表優缺點:
增加一個元素或者刪除一個元素都很難,因為地址是連續的,刪除一個元素可能會挪動多個元素,不靈活。但是對于鏈表來說就很輕松了,鏈表的每一個節點都是一個結構體,可以通過指針指向的方式將鏈表串起來,很靈活。
鏈表和數組的引入:
#include <stdio.h>
#include <stdlib.h>
//只要是通過指針的凡是訪問結構體中的數據都要用->
struct Text//用鏈表的形式存儲數據
{int data;struct Text* next;
};
int main()
{int i;int array[]={1,2,3,4};//用數組的方式實現數據的存儲,訪問到數組的首地址就可以輸出整個數組//因為數組的地址是連續的for(i=0;i<sizeof(array)/sizeof(array[0]);i++){printf("%d",array[i]);}putchar('\n');struct Text t1={1,NULL};struct Text t2={2,NULL};struct Text t3={3,NULL};//下面幾行代碼是將上面定義的幾個結構體串起來,形成鏈表t1.next=&t2;//指針是存放別人的地址t1里的指針變量指向t2的地址t2.next=&t3;//這樣就將三個結構體聯系了起來printf("use t1 printf four number:\n");printf("%d %d %d\n",t1.data,t1.next->data,t1.next->next->data);//t1.next就是指向t2的一個指針(我理解的就是相當于struct Text * p)//然后通過->這種方式去訪問結構體中的數據,然后t1.next->next就是相當于//指向t3的一個指針,也要通過->這種方式去訪問里面的數據system("pause");return 0;
}
鏈表的動態輸出:
#include <stdio.h>
#include <stdlib.h>
//只要是通過指針的凡是訪問結構體中的數據都要用->
struct Text//用鏈表的形式存儲數據
{int data;struct Text* next;
};void printLink(struct Text *head)//鏈表的動態輸出函數,struct Text *head是鏈表的頭
{struct Text*Point;Point=head;while(Point!=NULL){printf("%d ",Point->data);Point=Point->next;//head是第一個節點的指針,輸出完第一個鏈表的內容后,將鏈表的頭部往后移一個,變為指向第二個節點的指針//head->next是指向下一個鏈表的頭}putchar('\n');}
int main()
{int i;int array[]={1,2,3,4};//用數組的方式實現數據的存儲,訪問到數組的首地址就可以輸出整個數組//因為數組的地址是連續的for(i=0;i<sizeof(array)/sizeof(array[0]);i++){printf("%d",array[i]);}putchar('\n');struct Text t1={1,NULL};struct Text t2={2,NULL};struct Text t3={3,NULL};//下面幾行代碼是將上面定義的幾個結構體串起來,形成鏈表t1.next=&t2;//指針是存放別人的地址t1里的指針變量指向t2的地址t2.next=&t3;//這樣就將三個結構體聯系了起來printLink(&t1);//將第一個鏈表的地址傳入動態輸出函數system("pause");return 0;
}
鏈表的查找和節點個數的計算:
#include <stdio.h>
#include <stdlib.h>
//只要是通過指針的凡是訪問結構體中的數據都要用->
struct Text//用鏈表的形式存儲數據
{int data;struct Text* next;
};void printLink(struct Text *head)//鏈表的動態輸出函數,struct Text *head是鏈表的頭
{struct Text*Point;Point=head;while(Point!=NULL){printf("%d ",Point->data);Point=Point->next;//head是第一個節點的指針,輸出完第一個鏈表的內容后,將鏈表的頭部往后移一個,變為指向第二個節點的指針//head->next是指向下一個鏈表的頭}putchar('\n');}
void countLink(struct Text* head)//鏈表計算節點個數函數
{int cont=0;struct Text* Point;Point=head;while(head!=NULL){cont++;head=head->next;}printf("鏈表節點數為:%d\n",cont);}
void serchLink(struct Text*head,int data)
{while(head!=NULL){if(head->data==data){printf("存在此節點\n");return;}head=head->next;}printf("無此節點\n");
}
int main()
{int i;int input;int array[]={1,2,3,4};//用數組的方式實現數據的存儲,訪問到數組的首地址就可以輸出整個數組//因為數組的地址是連續的for(i=0;i<sizeof(array)/sizeof(array[0]);i++){printf("%d",array[i]);}putchar('\n');struct Text t1={1,NULL};struct Text t2={2,NULL};struct Text t3={3,NULL};//下面幾行代碼是將上面定義的幾個結構體串起來,形成鏈表t1.next=&t2;//指針是存放別人的地址t1里的指針變量指向t2的地址t2.next=&t3;//這樣就將三個結構體聯系了起來printLink(&t1);countLink(&t1);printf("請輸入要查找的節點:\n");scanf("%d",&input);serchLink(&t1,input);system("pause");return 0;
}
從指定節點后插入節點:
#include <stdio.h>
#include <stdlib.h>
//只要是通過指針的凡是訪問結構體中的數據都要用->
struct Text//用鏈表的形式存儲數據
{int data;struct Text* next;
};void printLink(struct Text *head)//鏈表的動態輸出函數,struct Text *head是鏈表的頭
{struct Text*Point;Point=head;while(Point!=NULL){printf("%d ",Point->data);Point=Point->next;//head是第一個節點的指針,輸出完第一個鏈表的內容后,將鏈表的頭部往后移一個,變為指向第二個節點的指針//head->next是指向下一個鏈表的頭}putchar('\n');}
void countLink(struct Text* head)//鏈表計算節點個數函數
{int cont=0;struct Text* Point;Point=head;while(head!=NULL){cont++;head=head->next;}printf("鏈表節點數為:%d\n",cont);}
void serchLink(struct Text*head,int data)
{while(head!=NULL){if(head->data==data){printf("存在此節點\n");return;}head=head->next;}printf("無此節點\n");
}void InsertFromBhind(struct Text*head,struct Text*newLink,int data)
{struct Text* Point;Point=head;while(Point!=NULL){if(Point->data==data){newLink->next=Point->next;//head->next是插入位置后一個節點的指針,就是head->next指向插入位置的后一個節點Point->next=newLink;//修改插入位置前一個節點內的指針指向,指向新節點的地址,將鏈表串起來printLink(head);return;}Point=Point->next;}printf("無此節點\n");
}
int main()
{int i;int input;int link;struct Text t1={1,NULL};struct Text t2={2,NULL};struct Text t3={3,NULL};struct Text t4={4,NULL};//下面幾行代碼是將上面定義的幾個結構體串起來,形成鏈表t1.next=&t2;//指針是存放別人的地址t1里的指針變量指向t2的地址t2.next=&t3;//這樣就將三個結構體聯系了起來printLink(&t1);countLink(&t1);printf("請輸入要查找的節點:\n");scanf("%d",&input);serchLink(&t1,input);printf("請輸入在哪個節點后插入;\n");scanf("%d",&link);InsertFromBhind(&t1,&t4,link);system("pause");return 0;
}
在指定節點前插入節點:
#include <stdio.h>
#include <stdlib.h>
//只要是通過指針的凡是訪問結構體中的數據都要用->
struct Text//用鏈表的形式存儲數據
{int data;struct Text* next;
};void printLink(struct Text *head)//鏈表的動態輸出函數,struct Text *head是鏈表的頭
{struct Text*Point;Point=head;while(Point!=NULL){printf("%d ",Point->data);Point=Point->next;//head是第一個節點的指針,輸出完第一個鏈表的內容后,將鏈表的頭部往后移一個,變為指向第二個節點的指針//head->next是指向下一個鏈表的頭}putchar('\n');}
void countLink(struct Text* head)//鏈表計算節點個數函數
{int cont=0;struct Text* Point;Point=head;while(head!=NULL){cont++;head=head->next;}printf("鏈表節點數為:%d\n",cont);}
void serchLink(struct Text*head,int data)
{while(head!=NULL){if(head->data==data){printf("存在此節點\n");return;}head=head->next;}printf("無此節點\n");
}
void InsertFromBefore(struct Text*head,struct Text*newlink,int data)
{struct Text*Point;Point=head;if(head!=NULL && head->data==data){newlink->next=head;printLink(newlink);return;}while(Point->next!=NULL){//因為是在指定節點前插入節點//所以要通過指定節點的前一個節點插入//Point就是指向,指定節點前一個節點的指針//Point->next是指向,指定的插入節點的指針,也就是在這個節點前插入節點if(Point->next->data==data){newlink->next=Point->next;Point->next=newlink;printLink(head);return;}Point=Point->next;}
}int main()
{int i;int input;int link;struct Text t1={1,NULL};struct Text t2={2,NULL};struct Text t3={3,NULL};struct Text t4={4,NULL};//下面幾行代碼是將上面定義的幾個結構體串起來,形成鏈表t1.next=&t2;//指針是存放別人的地址t1里的指針變量指向t2的地址t2.next=&t3;//這樣就將三個結構體聯系了起來printLink(&t1);countLink(&t1);printf("請輸入要查找的節點:\n");scanf("%d",&input);serchLink(&t1,input);printf("請輸入在哪個節點前插入;\n");scanf("%d",&link);InsertFromBefore(&t1,&t4,link);system("pause");return 0;
}
靜態鏈表的刪除和修改:
#include <stdio.h>
#include <stdlib.h>
//只要是通過指針的凡是訪問結構體中的數據都要用->
struct Text//用鏈表的形式存儲數據
{int data;struct Text* next;
};void printLink(struct Text *head)//鏈表的動態輸出函數,struct Text *head是鏈表的頭
{struct Text*Point;Point=head;while(Point!=NULL){printf("%d ",Point->data);Point=Point->next;//head是第一個節點的指針,輸出完第一個鏈表的內容后,將鏈表的頭部往后移一個,變為指向第二個節點的指針//head->next是指向下一個鏈表的頭}putchar('\n');}
void countLink(struct Text* head)//鏈表計算節點個數函數
{int cont=0;struct Text* Point;Point=head;while(head!=NULL){cont++;head=head->next;}printf("鏈表節點數為:%d\n",cont);}
void serchLink(struct Text*head,int data)//查找函數
{while(head!=NULL){if(head->data==data){printf("存在此節點\n");return;}head=head->next;}printf("無此節點\n");
}void changeLink(struct Text*head,int data,int data2)//改函數
{struct Text*Point=head;while(Point!=NULL){if(Point->data==data){printf("此節點存在可改\n");Point->data=data2;printLink(head);return;}Point=Point->next;}printf("無此節點\n");
}void delLink(struct Text*head,int data)
{struct Text*Point=head;if(head->data==data){head=head->next;//將第二個節點指定為數組頭,那么第一個節點就需要釋放掉避免造成內存泄漏//free(Point); //將這個地址釋放掉,可以通過Point指針將之前的head的內存空間釋放掉//free可以將指針指向的內存空間釋放掉,但是釋放掉之后最好將指針指向NULL//因為free只是把指針所指的內存給釋放掉,但并沒有把指針本身干掉。//free只能釋放malloc開辟的內存空間printLink(head);return;}while(Point->next!=NULL){//head->next是指向要刪除的那個節點的指針if(Point->next->data==data){Point->next=Point->next->next;//如果是動態創建,就要新定義一個指針//通過新定義的指針把(Ponit->next)free掉printLink(head);return;}Point=Point->next;}printf("沒有找到\n");
}
int main()
{int i;int input;int link;struct Text t1={1,NULL};struct Text t2={2,NULL};struct Text t3={3,NULL};struct Text t4={4,NULL};//下面幾行代碼是將上面定義的幾個結構體串起來,形成鏈表t1.next=&t2;//指針是存放別人的地址t1里的指針變量指向t2的地址t2.next=&t3;//這樣就將三個結構體聯系了起來printLink(&t1);countLink(&t1);printf("請輸入要查找的節點:\n");scanf("%d",&input);serchLink(&t1,input);printf("請輸入要刪除哪個節點;\n");scanf("%d",&link);delLink(&t1,link);printf("修改哪個節點;\n");scanf("%d",&link);changeLink(&t1,link,100);//這些所有的函數并不修改main函數中的節點system("pause");return 0;
}
鏈表的動態創建之頭插法(每插進來一個節點就將它當做頭結點,就像棧一樣)
#include <stdio.h>
#include <stdlib.h>struct Text
{int data;struct Text*next;
};
void printLink(struct Text *head)//鏈表的動態輸出函數,struct Text *head是鏈表的頭
{struct Text*Point;Point=head;while(Point!=NULL){printf("%d ",Point->data);Point=Point->next;//head是第一個節點的指針,輸出完第一個鏈表的內容后,將鏈表的頭部往后移一個,變為指向第二個節點的指針//head->next是指向下一個鏈表的頭 }putchar('\n');}
struct Text *creatFromHead(struct Text*head,struct Text*newnode)//節點頭插法插入函數
//節點創建函數和插入節點函數分開寫,有利于后面節點的插入
{if(head==NULL){head=newnode;}else{newnode->next=head;head=newnode;}return head;
}
struct Text*creatLink(struct Text*head)//鏈表節點創建函數
{struct Text*newnode=NULL;while(1){//不斷創建新的節點,直到輸入的數字為0newnode=(struct Text*)malloc(sizeof(struct Text));newnode->next=NULL;printf("請輸入data:\n");scanf("%d",&(newnode->data));if(newnode->data==0){free(newnode);//新創建的節點里的data等于0;所以不把他插入鏈表中//將它指向的內存空間釋放掉printf("鏈表創建結束\n");return head;}head=creatFromHead(head,newnode);}
}
int main()
{struct Text *head=NULL;printLink(creatLink(head));system("pause");return 0;
}
尾插法插入節點:
#include <stdio.h>
#include <stdlib.h>struct Text
{int data;struct Text*next;
};
void printLink(struct Text *head)//鏈表的動態輸出函數,struct Text *head是鏈表的頭
{struct Text*Point;Point=head;while(Point!=NULL){printf("%d ",Point->data);Point=Point->next;//head是第一個節點的指針,輸出完第一個鏈表的內容后,將鏈表的頭部往后移一個,變為指向第二個節點的指針//head->next是指向下一個鏈表的頭 }putchar('\n');}
struct Text *insertFromBehind(struct Text*head,struct Text*newnode)//節點尾插法插入函數
{struct Text* p=NULL;p=head;if(p==NULL){//如果沒有這句話,如果P為空指針,繼續往下執行p->next對空指針進行操作,會出現段錯誤head=newnode;return head;}while(p->next!=NULL){p=p->next;}p->next=newnode;return head;
}
struct Text*creatLink(struct Text*head)//鏈表節點創建函數
{struct Text*newnode=NULL;while(1){//不斷創建新的節點,直到輸入的數字為0newnode=(struct Text*)malloc(sizeof(struct Text));newnode->next=NULL;printf("請輸入data:\n");scanf("%d",&(newnode->data));if(newnode->data==0){free(newnode);//新創建的節點里的data等于0;所以不把他插入鏈表中//將它指向的內存空間釋放掉printf("鏈表創建結束\n");return head;}head=insertFromBehind(head,newnode);}
}
int main()
{struct Text *head=NULL;printLink(creatLink(head));system("pause");return 0;
}