链表基本操作及代码实现

涉及到单链表的基本操作有如下:

int initList(linkList *);  //初始化一个单链表,具有头指针,头结点,头结点->next=NULL;
int createListHead(linkList *, int n);  //头插法创建一个链表,链表长度为n;
int createListTail(linkList *, int n);  //尾插法创建一个链表,链表长度为n;
int getlength(linkList *);  //获取单链表的长度;
int printList(linkList *);  //打印整个链表;
int getElem(linkList *,int i,ElemType *);  //获取链表中第i个位置处节点的数据元素;
int insertList(linkList *, int i, ElemType data);  //在链表的指定位置(i节点)插入一个节点,i的范围为1~length(链表总长度);
int insertListTail(linkList *, ElemType data);  //给链表追加一个节点,在最末尾处增加;
int deleteList(linkList *, int i, ElemType *data);  //删除指定位置(i节点)处的节点,i的范围为1~length(链表总长度);
int clearList(linkList *);  //删除整个链表,使头结点->next=NULL;

(一)ADT:

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px 0px 0px 22px; white-space: pre-wrap; overflow-wrap: break-word; font-size: 12px !important; font-family: "Courier New" !important;">1 typedef int ElemType; 2 typedef struct Node { 3 ElemType data; 4 struct Node * next; 5 }Node; 6 typedef struct Node* linkList;</pre>

[
复制代码

](javascript:void(0); "复制代码")

*(二)初始化:int initList(linkList L)

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px 0px 0px 22px; white-space: pre-wrap; overflow-wrap: break-word; font-size: 12px !important; font-family: "Courier New" !important;">1 int initList(linkList L) 2 { 3 (L) = (linkList)malloc(sizeof(Node)); 4 (*L)->next = NULL; 5 printf("链表初始化成功\n"); 6 return 1; 7 }</pre>

[
复制代码

](javascript:void(0); "复制代码")

初始化一个指向头节点的指针,使头指针->next=NULL,头指针->data不做处理;

image

(三)创建一个单链表

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px 0px 0px 22px; white-space: pre-wrap; overflow-wrap: break-word; font-size: 12px !important; font-family: "Courier New" !important;"> 1 int createListHead(linkList L,int n) { 2 linkList p;
3 int i = 0;
4 srand((int)time(0));
5 for (i = 0; i < n; i++)
6 {
7 p= (linkList)malloc(sizeof(Node));
8 p->data = rand() % 100;
9 printf("testing:Node[%d]=%d\n",i+1,p->data); 10 p->next = (
L)->next; 11 (*L)->next = p; 12 } 13 printf("链表(头插法)创建成功\n"); 14 return 1; 15 }</pre>

[
复制代码

](javascript:void(0); "复制代码")

说明:

1、图中的head表示头指针,而在创建单链表中的入参phead是指向指针的指针;即phead等同于head,head指向头节点;

2、初始化和创建整表的函数中,为什么入参是linkList *类型的参数呢,为什么不是Node 类型的;之前我的理解是可以使用Node类型的入参,这样声明一个Node *head,这样在创建整表的函数中可以直接createList(head,10),直接传入头指针,但是尝试过以后,会在通过头指针访问各节点数据的时候,弹出错误窗口,原因还不太清楚;

3(补充)在看《C和指针》258的时候,看到了这么一句话,好像可以解释为什么需要传入链表的基本操作函数中的入参是一个指针类型的变量;

“i='a';pi='a';*ppi='a';  //这三条语句具有同样的效果;i-整型变量,pi-指向i的指针,ppi-指向pi指针的指针;

在一条简单的对i赋值的语句就可以完成任务的情况下,为什么还要使用更为复杂的涉及间接访问的方法呢?这是因为简单赋值并不总是可行,例如链表的插入。在那些函数中,我们无法使用简单赋值,因为变量名在函数的作用域内部是未知的。函数所拥有的只是一个指向需要修改的内存位置的指针,所以要对该指针进行间接访问操作以访问需要修改的变量。

image
       ![image](http://upload-images.jianshu.io/upload_images/12754558-89b755976c4429a3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px 0px 0px 22px; white-space: pre-wrap; overflow-wrap: break-word; font-size: 12px !important; font-family: "Courier New" !important;">int createListTail(linkList L, int n) {
linkList p, temp;
temp = (
L); int i;
srand((int)time(0)); for (i = 0; i < n;i++) {
p = (linkList)malloc(sizeof(Node));
p->data = rand() % 100;
printf("testing:Node[%d]=%d\n", i + 1, p->data);
p->next = NULL;
temp->next = p;
temp = p;
}
printf("链表(尾插法)创建成功\n"); return 1;
}</pre>

[
复制代码

](javascript:void(0); "复制代码")

image

(四)获取链表的长度

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px 0px 0px 22px; white-space: pre-wrap; overflow-wrap: break-word; font-size: 12px !important; font-family: "Courier New" !important;"> 1 int getlength(linkList L) {
2 linkList p;
3 int length=0;
4 p = (
L)->next;//p指向第一个节点;
5 while (p) { 6 length++;
7 p = p->next;
8 }
9 return length; 10 }</pre>

[
复制代码

](javascript:void(0); "复制代码")

(五)打印整个链表

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px 0px 0px 22px; white-space: pre-wrap; overflow-wrap: break-word; font-size: 12px !important; font-family: "Courier New" !important;"> 1 int printList(linkList L) {
2 linkList p;
3 int i = 0;
4 p = (
L)->next;//p指向第一个节点;
5 printf("-----------打印整个链表-----------\n");
6 if (p==NULL) {
7 printf("这是一个空链表.\n");
8 }
9 while (p) { 10 i++; 11 printf("第%d个节点的数据data为=%d\n",i,p->data); 12 p = p->next; 13 } 14 return 1; 15 }</pre>

[
复制代码

](javascript:void(0); "复制代码")

(六)获取指定位置处的节点元素;

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px 0px 0px 22px; white-space: pre-wrap; overflow-wrap: break-word; font-size: 12px !important; font-family: "Courier New" !important;"> 1 int getElem(linkList *L, int i, ElemType getdata) {
2 linkList p;
3 p = (
L)->next;
4 if (p == NULL) 5 {
6 printf("链表为空,请创建一个链表\n");
7 *getdata = -1;
8 return 0;
9 } 10 if (i < 1) 11 { 12 printf("您所查询的节点%d,应该大于0,请重新输入查询\n",i); 13 *getdata = -1; 14 return 0; 15 } 16 int j = 1; 17 while (p&&j<i) { 18 j++; 19 p = p->next; 20 } 21 if (p == NULL) 22 { 23 printf("您所查询的节点%d,已经超出了数组的长度\n",i); 24 *getdata = -1; 25 return 0; 26 } 27 *getdata = p->data; 28 printf("查询成功!\n", i); 29 return 1; 30 }</pre>

[
复制代码

](javascript:void(0); "复制代码")

(七)插入节点;

插入节点分为两种,一种是在链表的长度范围内插入节点,第二种是在链表的尾部追加一个节点;

假设链表的长度为10,第一种可以在1-10位置处插入节点,比如在第10个位置插入一个节点,则原先的第10节点变为了11节点,但是第二种是所有节点位置都不变,在第11个位置追加一个新的节点;

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px 0px 0px 22px; white-space: pre-wrap; overflow-wrap: break-word; font-size: 12px !important; font-family: "Courier New" !important;"> 1 int insertList(linkList L, int i, ElemType data) 2 {
3 linkList p;
4 linkList insNode;
5 p = (
L);
6 int j=0;
7 // 链表为空,在第1个位置插入一个新的节点;
8 if (p ->next == NULL) { 9 printf("链表为空,默认在第一个位置插入一个节点.\n"); 10 insNode = (linkList)malloc(sizeof(Node)); 11 insNode->data = data; 12 insNode->next = p->next; 13 p->next = insNode; 14 printf("节点插入成功.\n"); 15 return 1; 16 } 17 // 链表非空的情况下,可以在i=1~length的位置插入节点,如果超过了链表的长度,就会提示错误; 18 // 其实如果在length+1的位置处插入一个新节点,就相当于在尾部追加一个节点,在本函数中会报错,可以单独实现一个函数;
19 while(p && j<i-1) 20 { 21 j++; 22 p = p->next; 23 //printf("j=%d\tp->data=%d\n", j, p->data);
24 } 25 if (p->next==NULL) { 26 printf("您要插入的位置,超过了链表的长度 %d,请重新操作!\n",j); 27 return 0; 28 } 29 insNode = (linkList)malloc(sizeof(Node)); 30 insNode->data = data; 31 insNode->next = p->next; 32 p->next = insNode; 33
34 printf("节点插入成功\n"); 35 return 1; 36 }</pre>

[
复制代码

](javascript:void(0); "复制代码")

追加节点;

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px 0px 0px 22px; white-space: pre-wrap; overflow-wrap: break-word; font-size: 12px !important; font-family: "Courier New" !important;"> 1 int insertListTail(linkList L, ElemType data)
2 {
3 linkList temp;
4 linkList p=(
L);
5 while(p) {
6 temp = p; 7 p = p->next;
8 }
9 p = (linkList)malloc(sizeof(Node)); 10 p->data = data; 11 p->next = NULL; 12 temp->next = p; 13 printf("节点插入成功\n"); 14 return 1; 15 }</pre>

[
复制代码

](javascript:void(0); "复制代码")

(八)删除节点;

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px 0px 0px 22px; white-space: pre-wrap; overflow-wrap: break-word; font-size: 12px !important; font-family: "Courier New" !important;"> 1 int deleteList(linkList *L, int i, ElemType data)
2 {
3 linkList p,pnext;
4 int j = 0;
5 p = (
L);
6 if (p->next == NULL) { 7 printf("链表为空,无法删除指定节点.\n");
8 *data = -1;
9 return 0; 10 } 11 while (p->next && j<i-1) { 12 j++; 13 p = p->next; 14 //printf("j=%d\t p->data=%d\n",j,p->data);
15 }//条件最多定位到最后一个节点;
16 if ( p->next == NULL) { 17 printf("您要删除的节点,超过了链表的长度 %d,请重新操作!\n", j); 18 *data = -1; 19 return 0; 20 } 21 pnext = p->next; 22 p->next = pnext->next; 23 *data = pnext->data; 24 free(pnext); 25 printf("节点删除成功\n"); 26 return 1; 27 }</pre>

[
复制代码

](javascript:void(0); "复制代码")

(九)删除这个链表;

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px 0px 0px 22px; white-space: pre-wrap; overflow-wrap: break-word; font-size: 12px !important; font-family: "Courier New" !important;"> 1 int clearList(linkList L) {
2 linkList p, temp;
3 p = (
L)->next;//p指向第一个节点
4 while (p) { 5 temp = p; 6 p = p->next;
7 free(temp);
8 }
9 (*L)->next = NULL; 10 printf("整个链表已经clear.\n"); 11 return 1; 12 }</pre>

[
复制代码

](javascript:void(0); "复制代码")

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容