典型数据结构:数组、链表、队列、栈、二叉树、Hash表、图
一、链表
1、头指针和头结点
头指针
a) 头指针是指向链表第一个结点的指针,如果存在头结点,头指针就是指向头结点的指针。
b) 头指针具有标识作用,常用头指针冠以链表的名字
c) 无论链表是否为空,头指针均不为空(对此句话不认同)。头指针是链表的必要元素。
头结点
a) 头结点是为了操作的统一和方便而设立的,位于第一个数据节点之前,其数据域一般无意义(也可以存放链表的长度)。
b) 有了头结点,在第一元素前插入节点和删除第一节点,其操作与其他节点的操作就统一了。
c) 头结点不是链表的必要元素。
头指针只是一个指针,没有实例化;头结点是一个实例化的节点。
2、链表的程序实现
1)注意:在main函数里面定义的linklist list; 这个地方定义的是头指针,头结点在creat()函数里面创建,头结点是占有实际空间的,需要动态分配内存。
creat1(&list,3); //由于creat1()函数需要创建头结点,而头指针(即list)需要指向头结点,list原来是空,在函数里要改变,要想保留结果必须将其指针传入函数内部。注意c语言不能引用,但是可以传递指针,此处是提取指针,不要混淆掉。插入和删除虽然会改变链表,但是不会改变头指针,所以不用定义为linklist的指针(虽然书上这样写)。
2)双链表和单链表的操作大部分相同,因为只要朝一个方向遍历就可以。构造、插入和删除函数,有区别。一般涉及3个节点,4条连接。
注意,双链表初始的时候,只有头结点,头结点的prior指针和next指针均指向自身。
#include<iostream>
using namespace std;
/*
注意这里linklist是节点的指针类型,一般用于定义头指针,由于头指针具有标识作用,所以可以认为其是用来定义链表的。
*/
typedef struct node
{
int data;
node *next;
}node,*linklist;
/*
获取第i个元素值。注意,尽量用指针,因为C不支持引用
*/
bool getelem(linklist l,int i,int *elem)
{
node *p = l->next;
/*
确定边界最好的办法就是假设一种情形,边界设
置好的话,操作的形式会统一地很好。
*/
while ((i > 1)&&(p!=NULL))
{
p = p->next;
i--;
}
if (p == NULL) return false;
*elem = p->data;
return true;
}
/*
在第i个元素前,插入元素。
*/
bool linsert(linklist l, int i, int elem)
{
node* p = l;
while ((i > 1) && (p != NULL))
{
p = p->next;
i--;
}
if (p == NULL) return false;
/*
C++和C动态分配存储的方式不同,malloc返回的指针是void的,必须强制转换。C++为struct提供默认的构造函数
*/
node *temp = (node*)malloc(sizeof(node));
//node *temp=new node();
temp->next = p->next;
temp->data = elem;
p->next = temp;
return true;
}
/*
删除第i个元素,并将值赋给elem,删除的时候,要先保留删除位置,否则会丢失
*/
bool ldelete(linklist l,int i,int *elem)
{
node* p = l;
while ((i>1)&&(p->next!=NULL))
{
p = p->next;
i--;
}
node *q = p->next;
if (q == NULL) return false;
*elem = q->data;
p->next = q->next;
free(q);
return true;
}
bool creat1(linklist *l, int n) //头插
{
*l = (node *)malloc(sizeof(node));
(*l)->next = NULL; //指针一定要初始化
while (n > 0)
{
node *temp = (node *)malloc(sizeof(node));
temp->next = (*l)->next;
temp->data = n;
(*l)->next = temp;
n--;
}
return true;
}
bool creat2(linklist *l, int n) //尾插
{
node *tail;
(*l) = (node *)malloc(sizeof(node));
(*l)->next = NULL;
tail = *l;
while (n > 0)
{
node *temp = (node *)malloc(sizeof(node));
temp->next = NULL;
temp->data = n;
tail->next = temp;
tail = temp;
n--;
}
return true;
}
void lprint(linklist l)
{
node *p = l->next;
while (p != NULL)
{
cout << p->data<<" ";
p = p->next;
}
cout << endl;
}
int main()
{
linklist list; //这个地方定义的是头指针,头结点在creat函数里面创建,头结点是占有实际空间的,需要动态分配内存
linklist list2;
int a;
list = NULL;
cout << "原始:" << endl;
creat1(&list,3); //由于,creat函数需要创建头结点,而头指针(即list)需要指向头结点,
//list原来是空,在函数里要改变,要想保留结果必须将其指针传入函数内
//部。注意c语言不能引用,但是可以传递指针,此处是提取指针,不要混淆掉。
lprint(list);
cout << "删除后:" << endl;
ldelete(list,1,&a);
lprint(list);
cout << "插入后:" << endl;
linsert(list,2,7);
lprint(list);
cout << "尾部插入方式:" << endl;
creat2(&list2, 3);
lprint(list2);
system("pause");
return 0;
}
#include<iostream>
using namespace std;
typedef struct node
{
int data;
node *prior;
node *next;
}node, *linklist;
/*
第i个节点前插入元素elem
*/
bool linsert(linklist l, int i, int elem)
{
node *q;
node *p = l->next;;
while ((i > 1) && (p != NULL))
{
p = p->next;
i--;
}
if (p == NULL) return false;
node *temp = (node*)malloc(sizeof(node));
temp->data = elem;
/*插入操作涉及3个节点*/
q = p->prior;//q是第一个节点,temp是第二个节点,p是第三个节点
q->next = temp;
temp->prior = q;
temp->next = p;
p->prior = temp;
return true;
}
bool ldelete(linklist l,int i,int *elem)
{
node *p = l->next;
while ((i > 1) && (p != NULL))
{
p = p->next;
i--;
}
if (p == NULL) return false;
node *q,*r;
*elem = p->data;
q = p->prior;
r = p->next;
q->next = r;
r->prior = q;
return true;
}
void creat(linklist *list,int n)
{
(*list) = (node*)malloc(sizeof(node));
(*list)->next = (*list);
(*list)->prior = (*list);
node *p = (*list);
node *r;
while (n > 0)
{
/*类似插入,也是有3个节点*/
node *temp = (node*)malloc(sizeof(node));
temp->data = n;
r = p->next;
p->next = temp;
temp->prior = p;
temp->next = r;
r->prior = temp;
n--;
}
}
void lprint(linklist l)
{
node *p;
p = l->next;
while (p != l)
{
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
int main()
{
int a;
linklist list=NULL;
creat(&list, 3);
lprint(list);
linsert(list,2,7);
lprint(list);
ldelete(list,3,&a);
lprint(list);
system("pause");
return 0;
}