单向循环链表
特点:
链表 + 尾结点指向头结点
注意:
在单向不循环链表的基础上修改判断尾结点的条件。 p->pNext == NULL ==> p->pNext == pList
笔试题:
合并两个已知尾结点的单向循环链表。
LIST * mergeList(LIST *pT1,LIST * pT2)
{
if( NULL == pT1)
{
return pT2;
}
if( NULL == pT2)
{
return pT1;
}
if( NULL == pT1 ->pNext )
{
free(pT1);
return pT2;
}
if( pT2 == pT2->pNext)
{
free(pT2);
return pT1;
}
//定义一个指针p指向准备释放的头节点
LIST * p = pT1->pNext;
//将pT1作为合并后链表的尾节点,指向头节点
pT1->pNext = pT2->pNext;
//将pT2指向pT1原链表的首节点
pT2->pNext = p->pNext;
//释放p
free(p);p=NULL;
return pT1;
}
双向链表
特点 :
每一个结点有一个数据域,有两个指针域,分别指向前一个结点和后一个结点。
双向循环链表
笔试题:
1. 合并两个已知尾结点的单向循环链表。
2. 合并两个有序链表,使它成为一个有序链表。
3. 链表排序
4. 链表逆序
5. 链表的删除
注意:
写一个函数API来实现上面的某个功能
在这个API中尽量不要出现malloc。
栈
特点:
操作受限的线性表。
能操作的一端叫栈顶,不能操作的一端叫栈底,遵循先入后出。
存储方式
顺序存储 链式存储
顺序栈
特点:
地址连续 大小固定 紧凑 访问栈顶方便
插入和删除只能在栈顶进行 遵循先入后出(FILO)
定义一个数据类型来描述顺序栈
typedef ** data_t;
struct stack
{
data_t data[SIZE];
int count;
};
或者
struct stack
{
data_t * pData;
int len;
int count;
};
顺序栈的操作
创建栈
与创建顺序表一样
入栈
与顺序表的尾插一样
出栈
与顺序表的尾删一样
查看栈顶元素
输出count-1位置的元素
销毁栈
与销毁顺序表一样
链式栈
特点:
地址不一定连续 大小不固定 插入和删除只能在栈顶进行 遵循先入后出(FILO)
定义一个数据类型来描述链式栈
struct stack
{
data_t data;
struct stack * pNext;
};
相关操作
创建栈
和创建链表一样
入栈
和链表的头插法一样
出栈
和链表的头删法一样
查看栈顶元素
查看首结点的元素
销毁栈
和销毁链表一样
队列
特点
操作受限的线性表。
入队的一端叫队尾,出队的一端叫队头,它遵循先入先出。
存储方式
顺序存储 链式存储
顺序队列
特点:
地址连续 大小固定 访问方便 紧凑存储 遵循先入先出FIFO
队头进行出队,队尾进行入队
定义一个数据类型来描述顺序队列
struct queue
{
data_t data[SIZE];
int count;
};
顺序队列的操作
创建队列
和创建顺序表一样
入队
和顺序表的头插法一样
出队
和顺序表的尾删法一样
查看队头元素
查看下标为count-1的元素
查看队尾元素
查看下标为0的元素
销毁队列
和销毁顺序表一样
判断队空
和顺序表的判断空一样 if (0 == count) ...
链式队列
特点:
地址不一定连续 大小不固定 遵循先入先出FIFO
队头进行出队,队尾进行入队
定义一个数据类型来描述链式队列
struct queue
{
data_t data;
struct queue * pNext;
};
链式队列的操作
创建队列
和创建链表一样
入队
和链表的尾插一样
出队
和链表的头删一样
查看队头元素
查看首结点的元素
查看队尾元素
查看链表尾结点的元素
判断队空
和判断链表的空是一样的
销毁队列
和销毁链表一样