用C語言寫出帶頭結點的鏈表
今天有一位學弟在網上向我求助,讓我幫他寫c語言帶頭結點的鏈表題目。
我想了想,c語言我有一年半載沒有接觸了。正好溫習溫習一下,就寫下此博客,來回顧一下我學習c語言的汗(Lei)水(Shui)與快(Tong)樂(Ku)。
那些帶頭結點的鏈表的題目
我先展示一下那位學弟的題目吧!
編程實現如下函數:
1、創建一個帶頭結點的單鏈表;
2、打印輸出該單鏈表;
3、在單鏈表中查找元素x,找到後則【在x之前】插入元素y
4、假設單鏈表是有序的,向該單鏈表插入元素x,使得插入後依舊有序;
5、刪除單鏈表中值爲x的所有元素
6、給定兩個升序的單鏈表ha、hb,將其合併爲【升序的】hc。要求:利用原表空間(即hc中的結點從ha、hb中摘取,不能再重新分配空間)
7、給定兩個升序的單鏈表ha、hb,將其合併爲【降序的】hc。要求:利用原表空間(即hc中的結點從ha、hb中摘取,不能再重新分配空間)
8、將單鏈表中的最小值結點【摘除】,插入該單鏈表的頭(即作爲該單鏈表的第一個元素)。
我們應該知道帶頭結點的鏈表和不帶頭結點的鏈表之間的差別:帶頭結點的鏈表就是犧牲一個空間來方便鏈表的增、刪、改、找。我們討論的情況就能更少一些,相對應的代碼量也會更少一些。
我們現在就各項突破這些題目!!!
必要代碼
我們做鏈表題目時,總時要有公共部分來支撐,就像“打地基”一樣,沒有把“底層”做好,很難去進行下一步操作。所以我把必要的代碼稱爲公共部分。就是這些代碼幾乎每一道題都要用上。
定義一個結構體
#include <stdio.h>
#include <stdlib.h>
typedef int datatype;
typedef struct link_node{
datatype info;
struct link_node *next;
}node;
typedef node *linklist;
首先 typedef int datatype; 就是給int 取一個別名,這個別名叫做 datatype。那麼datatype 就有和int 一樣的功能。
struct 就是結構體的意思,所以我們用struct定義一個結構體,毫無違和感。
typedef struct link_node{…} node;就是給struct link_node{…}這個結構體取個別名叫做node。
以前我一直搞不懂*struct link_node next; 這個語句是什麼意思。
現在想想倒是有了一個理解:官方一些就是將next聲明爲指向link_node 的指針。就是指針next指向link_node。
通俗一些的理解:就好比老鷹抓小雞遊戲裏的“小雞們”。每一個人的手抓住前一個人的衣角,手相當於指針next,衣角相當於link_node。這樣一個一個相連,就成了C語言的鏈表。不知道這樣理解形象不形象。如果還有更好的理解,可以在評論區裏評論。
創建一個帶頭結點的單鏈表
/***************************************
函數名稱:creatbyqueue()
函數功能:尾插法建立帶頭結點的單鏈表
備註:第一題答案,公共函數,之後每題必用
***************************************/
linklist creatbyqueue()
{
linklist head,r,s;
datatype x;
head=r=(linklist)malloc(sizeof(node));
head->next=NULL;
printf("請輸入整數序列(空格分開,以0結束):\n");
scanf("%d",&x);
while (x!=0)
{
s=(linklist)malloc(sizeof(node));
s->info=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL;
return head;
}
這是用尾插法建立帶頭結點的單鏈表。就像排隊一樣,先進先出,先輸入就可以先輸出。
具體怎麼實現的,用文字難以描述,等我有了充足的時間會在補全來的。之後我的解析更多的在代碼
既然有尾插法,那就有頭插法。頭插法相對來講更簡單一些,但是輸出時確實倒序輸出。
/******************************************
函數名稱:creatbystack()
函數功能:頭插法建立帶頭結點的單鏈表
******************************************/
linklist creatbystack()
{
linklist head,s;
datatype x;
head=(linklist)malloc(sizeof(node));
head->next=NULL;
printf("請輸入整數序列(空格分開,以0結束):\n");
scanf("%d",&x);
while (x!=0)
{
s=(linklist)malloc(sizeof(node));
s->info=x;
s->next=head->next;
head->next=s;
scanf("%d",&x);
}
return head;
}
打印輸出該單鏈表
/**********************************
函數名稱:print()
函數功能:輸出帶頭結點的單鏈表
備註:第二題答案,公共函數,之後每題必用
**********************************/
void print(linklist head)
{
linklist p;
int i=0;
p=head->next;
printf("List is:\n");
while(p)
{
printf("%7d",p->info);
i++;
if (i%10==0) printf("\n");
p=p->next;
}
printf("\n");
}
釋放鏈表內存空間(容易忘記)
/**********************************
函數名稱:delList()
函數功能:釋放帶頭結點的單鏈表
備註:公共函數,之後每題必用。(容易忘記寫的一個函數)
**********************************/
void delList(linklist head)
{ linklist p=head;
while (p)
{ head=p->next;
free(p);
p=head;
}
}
題目
前三道題答案
題目:
1、創建一個帶頭結點的單鏈表;
2、打印輸出該單鏈表;
3、在單鏈表中查找元素x,找到後則【在x之前】插入元素y
第三道題核心代碼
/***********************************
函數名稱:find_x_insert_y()
函數功能:查找元素x,在x前面插入y。
備註:第三題答案
**********************************/
linklist find_x_insert_y(linklist chain, datatype x, datatype y)
{
linklist q, pre = chain;
q = chain->next;
while (q && q->info != x) //沒找完並且沒找到
{
pre = q;
q = q->next;
}
if (q) //表示q->info == x,即找到了x,那麼就在x前面插入y
{
linklist num;
num = (linklist)malloc(sizeof(node));
num->info = y;
num->next = pre->next;
pre->next = num;
}
else //表示沒有找到x;
{
printf("抱歉!沒有找到x~~");
}
return chain;
}
前三道題的主函數代碼
int main()
{
linklist chain;
datatype y, x;
//1、創建一個帶頭結點的單鏈表;(尾插法)
chain = creatbyqueue();
//2、打印輸出該單鏈表;
print(chain);
//3、在單鏈表中查找元素x,找到後則【在x之前】插入元素y
printf("請輸入你要查找的值:");
scanf("%d", &x);
printf("請輸入要插入的值:");
scanf("%d", &y);
chain = find_x_insert_y(chain, x, y);
printf("打印查看\n");
print(chain);
printf("釋放鏈表!\n");
delList(chain);
return 0;
}
第四道題答案
4、假設單鏈表是有序的,向該單鏈表插入元素x,使得插入後依舊有序;
第四道題核心代碼
/************************************************
函數名稱:insert_x()
函數功能:假設單鏈表是有序的,向該單鏈表插入元素x,使得插入後依舊有序;
備註:第四題答案。
************************************************/
linklist insert_x(linklist chain ,datatype x)
{
linklist pre=chain,q,sert;
q=chain->next;
while(q&&q->info<x) //沒找完並且小於x
{
pre=q;
q=q->next;
}
if(q) //表示q->info >= x,即找到了x,那麼就在q->info前面插入x
{
sert=(linklist)malloc(sizeof(node));
sert->info=x;
sert->next=pre->next;
pre->next=sert;
}
else //表示x比整個鏈表中的數都大,所以要插在鏈表的末尾。
{
sert=(linklist)malloc(sizeof(node));
sert->info=x;
pre->next=sert;
sert->next=q;
}
return chain;
}
第四道題主函數代碼
int main()
{
linklist chain;
datatype x;
//創建一個帶頭結點的單鏈表;(尾插法)
chain = creatbyqueue();
printf("打印查看\n");
print(chain);
printf("請輸入要插入的值:");
scanf("%d", &x);
//4、假設單鏈表是有序的,向該單鏈表插入元素x,使得插入後依舊有序;
insert_x(chain, x);
printf("打印查看\n");
print(chain);
printf("釋放鏈表!\n");
delList(chain);
return 0;
}
第五道題答案
5、刪除單鏈表中值爲x的所有元素
第五道題核心代碼
/**************************************
函數名稱:delete_all_x()
函數功能:刪除單鏈表中值爲x的所有元素
備註:第五題答案。
***************************************/
void delete_all_x(linklist chain, datatype x)
{
linklist pre,q;
int flag = 0;
pre=chain;
q=chain->next;
while(q)
{
while (q &&q->info!=x) //沒找完並且沒找到
{
pre=q;
q=q->next;
}
if (q) //表示q->info == x,那麼就刪除該結點
{
flag ++;
pre->next=q->next;
free(q);
q=pre->next; //刪除後q回到pre的後繼結點
}
}
if (flag==0)
printf("未找到值爲x=%d的結點!所以沒有刪除結點!\n", x);
else
printf("值爲x=%d的結點一共有%d個,現已全部刪除!\n", x, flag);
第五道題主函數代碼
int main()
{ datatype x;
linklist chain;
chain=creatbyqueue();
printf("打印查看\n");
print(chain);
printf("請輸入要刪除的值:");
scanf("%d",&x);
//5、刪除單鏈表中值爲x的所有元素
delete_all_x(chain, x);
printf("打印查看\n");
print(chain);
printf("釋放鏈表!\n");
delList(chain);
return 0;
}
第六道題答案
6、給定兩個升序的單鏈表ha、hb,將其合併爲【升序的】hc。要求:利用原表空間(即hc中的結點從ha、hb中摘取,不能再重新分配空間)
第六道題核心代碼
/*****************************************
函數名稱:chain_ascend()
函數功能:給定兩個升序的單鏈表ha、hb,將其合併爲【升序的】hc。要求:利用原表空間(即hc中的結點從ha、hb中摘取,不能再重新分配空間)
備註:第六題答案
*****************************************/
linklist chain_ascend(linklist ha,linklist hb)
{
linklist hc,rc,p,q;
hc=rc=(linklist)malloc(sizeof(node));
p=ha->next;
q=hb->next;
while (p && q)
{
if (p->info<q->info)
{
ha->next=p->next;
rc->next=p;
rc=p;
p=ha->next;
}
else
{
hb->next=q->next;
rc->next=q;
rc=q;
q=hb->next;
}
}
if (p) rc->next=p;
if (q) rc->next=q;
free(ha);
free(hb);
return hc;
}
第六道題主函數代碼
int main()
{
linklist ha,hb,hc;
//尾插法建立單鏈表,請輸入升序序列
ha=creatbyqueue();
hb=creatbyqueue();
printf("打印查看\n");
print(ha);
print(hb);
//升序合併到 hc
hc=chain_ascend(ha,hb);
printf("打印查看合併升序鏈表\n");
print(hc);
printf("釋放鏈表!\n");
delList(hc);
return 0;
}
第七道題答案
7、給定兩個升序的單鏈表ha、hb,將其合併爲【降序的】hc。要求:利用原表空間(即hc中的結點從ha、hb中摘取,不能再重新分配空間)
第七道題核心代碼
/*************************************
函數名稱:chain_descend()
函數功能:給定兩個升序的單鏈表ha、hb,將其合併爲【降序的】hc。要求:利用原表空間(即hc中的結點從ha、hb中摘取,不能再重新分配空間)
備註:第七題答案
**************************************/
linklist chain_descend(linklist ha,linklist hb)
{
linklist hc,p,q;
hc=(linklist)malloc(sizeof(node));
hc->next=NULL;
p=ha->next;
q=hb->next;
while (p && q)
{
if (p->info<q->info)
{
ha->next=p->next;
p->next=hc->next;
hc->next=p;
p=ha->next;
}
else
{
hb->next=q->next;
q->next=hc->next;
hc->next=q;
q=hb->next;
}
}
while (p)
{
ha->next=p->next;
p->next=hc->next;
hc->next=p;
p=ha->next;
}
while (q)
{
hb->next=q->next;
q->next=hc->next;
hc->next=q;
q=hb->next;
}
free(ha);
free(hb);
return hc;
}
第七道題主函數代碼
int main()
{
linklist ha,hb,hc;
//尾插法建立單鏈表,請輸入升序序列
ha=creatbyqueue();
hb=creatbyqueue();
printf("打印查看\n");
print(ha);
print(hb);
//降序合併到 hc
hc=chain_descend(ha,hb);
printf("打印查看合併降序鏈表\n");
print(hc);
printf("釋放鏈表!\n");
delList(hc);
return 0;
}
第八道題答案
8、將單鏈表中的最小值結點【摘除】,插入該單鏈表的頭(即作爲該單鏈表的第一個元素)。
第八道題核心代碼
/***************************************
函數名字:find_min_insert_head()
函數功能:將單鏈表中的最小值結點【摘除】,插入該單鏈表的頭(即作爲該單鏈表的第一個元素)。
備註:第八題答案
****************************************/
linklist find_min_insert_head(linklist chain)
{
linklist head=chain, pre = chain, q=chain->next;
datatype x;
x = q->info;
//先找到最小值
while (q)
{
if (q->info<=x)
x = q->info;
q = q->next;
}
//初始化
q = chain->next;
while (q->info != x)
{
pre = q;
q = q->next;
}
pre->next = q->next;
q->next = head->next;
head->next = q;
return chain;
}
第八道題主函數代碼
int main()
{
linklist chain;
chain = creatbyqueue();
printf("打印查看\n");
print(chain);
chain = find_min_insert_head(chain);
printf("打印查看將最小值放入頭節點的鏈表\n");
print(chain);
printf("釋放鏈表!\n");
delList(chain);
return 0;
}